hfs 0.52.0-alpha3 → 0.52.0-beta4
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/index-gtPWo_px.js +809 -0
- package/admin/assets/{sha512-KoJbeciZ.js → sha512-3tDoWWX4.js} +1 -1
- package/admin/index.html +1 -1
- package/frontend/assets/{index-9d6fXdcb.css → index-Kys6yJtN.css} +1 -1
- package/frontend/assets/index-SY22o0dA.js +101 -0
- package/frontend/assets/{sha512-iUJsiv7j.js → sha512-I2H28VIm.js} +1 -1
- package/frontend/index.html +2 -2
- package/package.json +1 -1
- package/src/api.get_file_list.js +1 -1
- package/src/api.log.js +22 -42
- package/src/apiMiddleware.js +4 -0
- package/src/const.js +1 -1
- package/src/cross.js +9 -1
- package/src/errorPages.js +2 -2
- package/src/frontEndApis.js +8 -2
- package/src/langs/hfs-lang-it.json +2 -1
- package/src/misc.js +2 -3
- package/src/nat.js +3 -2
- package/src/serveFile.js +1 -1
- package/src/serveGuiAndSharedFiles.js +1 -1
- package/admin/assets/index-5H9ny4iP.js +0 -808
- package/frontend/assets/index-25y2vRgI.js +0 -101
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{g as OF,c as UF}from"./index-
|
|
1
|
+
import{g as OF,c as UF}from"./index-SY22o0dA.js";function gF(sF,hF){for(var eF=0;eF<hF.length;eF++){const tF=hF[eF];if(typeof tF!="string"&&!Array.isArray(tF)){for(const w in tF)if(w!=="default"&&!(w in sF)){const lF=Object.getOwnPropertyDescriptor(tF,w);lF&&Object.defineProperty(sF,w,lF.get?lF:{enumerable:!0,get:()=>tF[w]})}}}return Object.freeze(Object.defineProperty(sF,Symbol.toStringTag,{value:"Module"}))}var dF={exports:{}};/*
|
|
2
2
|
* [js-sha512]{@link https://github.com/emn178/js-sha512}
|
|
3
3
|
*
|
|
4
4
|
* @version 0.8.0
|
package/frontend/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0" />
|
|
6
6
|
<link href="/fontello.css" rel="stylesheet" />
|
|
7
7
|
<script src="//polyfill.io/v3/polyfill.min.js?features=es2022%2Ces2021%2Ces2020%2Ces2019%2Ces2018%2Ces2017"></script>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-SY22o0dA.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Kys6yJtN.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
package/package.json
CHANGED
package/src/api.get_file_list.js
CHANGED
|
@@ -28,7 +28,7 @@ const get_file_list = async ({ uri = '/', offset, limit, search, c, onlyFolders,
|
|
|
28
28
|
return fail(const_1.HTTP_METHOD_NOT_ALLOWED);
|
|
29
29
|
offset = Number(offset);
|
|
30
30
|
limit = Number(limit);
|
|
31
|
-
const filter = (0, misc_1.pattern2filter)(search);
|
|
31
|
+
const filter = (0, misc_1.pattern2filter)(String(search || ''));
|
|
32
32
|
const walker = (0, vfs_1.walkNode)(node, { ctx: admin ? undefined : ctx, onlyFolders, depth: search ? Infinity : 0 });
|
|
33
33
|
const onDirEntryHandlers = (0, plugins_1.mapPlugins)(plug => plug.onDirEntry);
|
|
34
34
|
const can_upload = admin || (0, vfs_1.hasPermission)(node, 'can_upload', ctx);
|
package/src/api.log.js
CHANGED
|
@@ -8,11 +8,24 @@ const consoleLog_1 = require("./consoleLog");
|
|
|
8
8
|
const cross_1 = require("./cross");
|
|
9
9
|
const events_1 = __importDefault(require("./events"));
|
|
10
10
|
const log_1 = require("./log");
|
|
11
|
-
const fs_1 = require("fs");
|
|
12
|
-
const readline_1 = __importDefault(require("readline"));
|
|
13
11
|
const misc_1 = require("./misc");
|
|
14
12
|
const SendList_1 = require("./SendList");
|
|
13
|
+
const serveFile_1 = require("./serveFile");
|
|
15
14
|
exports.default = {
|
|
15
|
+
async get_log_file({ file = 'log', range = '' }, ctx) {
|
|
16
|
+
const log = lodash_1.default.find(log_1.loggers, { name: file });
|
|
17
|
+
if (!log)
|
|
18
|
+
throw cross_1.HTTP_NOT_FOUND;
|
|
19
|
+
if (!log.path)
|
|
20
|
+
throw cross_1.HTTP_NOT_ACCEPTABLE;
|
|
21
|
+
ctx.attachment(log.path);
|
|
22
|
+
if (range)
|
|
23
|
+
ctx.request.header.range = `bytes=${range}`;
|
|
24
|
+
if (ctx.method === 'POST') // this would cause method_not_allowed
|
|
25
|
+
ctx.method = 'GET';
|
|
26
|
+
await (0, serveFile_1.serveFile)(ctx, log.path);
|
|
27
|
+
return null;
|
|
28
|
+
},
|
|
16
29
|
get_log({ file = 'log' }, ctx) {
|
|
17
30
|
return new SendList_1.SendListReadable({
|
|
18
31
|
bufferTime: 10,
|
|
@@ -27,48 +40,15 @@ exports.default = {
|
|
|
27
40
|
events_1.default.on('console', x => list.add(x));
|
|
28
41
|
return;
|
|
29
42
|
}
|
|
30
|
-
|
|
31
|
-
if (!logger)
|
|
43
|
+
if (!lodash_1.default.find(log_1.loggers, { name: file }))
|
|
32
44
|
return list.error(cross_1.HTTP_NOT_FOUND, true);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
39
|
-
input.on('end', () => list.ready());
|
|
40
|
-
input.on('ready', () => {
|
|
41
|
-
readline_1.default.createInterface({ input }).on('line', line => {
|
|
42
|
-
if (ctx.aborted)
|
|
43
|
-
return input.close();
|
|
44
|
-
const obj = parse(line);
|
|
45
|
-
if (obj)
|
|
46
|
-
list.add(obj);
|
|
47
|
-
}).on('close', () => {
|
|
48
|
-
ctx.res.once('close', (0, misc_1.onOff)(events_1.default, {
|
|
49
|
-
[logger.name](entry) {
|
|
50
|
-
list.add(entry);
|
|
51
|
-
}
|
|
52
|
-
}));
|
|
53
|
-
});
|
|
54
|
-
});
|
|
45
|
+
list.ready();
|
|
46
|
+
ctx.res.once('close', (0, misc_1.onOff)(events_1.default, {
|
|
47
|
+
[file](entry) {
|
|
48
|
+
list.add(entry);
|
|
49
|
+
}
|
|
50
|
+
}));
|
|
55
51
|
}
|
|
56
52
|
});
|
|
57
|
-
function parse(line) {
|
|
58
|
-
const m = /^(.+?) (.+?) (.+?) \[(.{11}):(.{14})] "(\w+) ([^"]+) HTTP\/\d.\d" (\d+) (-|\d+) ?(.*)/.exec(line);
|
|
59
|
-
if (!m)
|
|
60
|
-
return;
|
|
61
|
-
const [, ip, , user, date, time, method, uri, status, length, extra] = m;
|
|
62
|
-
return {
|
|
63
|
-
ip,
|
|
64
|
-
user: user === '-' ? undefined : user,
|
|
65
|
-
ts: new Date(date + ' ' + time),
|
|
66
|
-
method,
|
|
67
|
-
uri,
|
|
68
|
-
status: Number(status),
|
|
69
|
-
length: length === '-' ? undefined : Number(length),
|
|
70
|
-
extra: (0, cross_1.tryJson)((0, cross_1.tryJson)(extra)) || undefined,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
53
|
},
|
|
74
54
|
};
|
package/src/apiMiddleware.js
CHANGED
|
@@ -44,11 +44,15 @@ function apiMiddleware(apis) {
|
|
|
44
44
|
else if (typeof (v === null || v === void 0 ? void 0 : v[0]) === 'string')
|
|
45
45
|
v.forEach((x, i) => fixUri(v, i));
|
|
46
46
|
res = await apiFun(params, ctx);
|
|
47
|
+
if (res === null)
|
|
48
|
+
return;
|
|
47
49
|
function fixUri(obj, k) {
|
|
48
50
|
obj[k] = (0, misc_1.removeStarting)(ctx.state.revProxyPath, obj[k]);
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
catch (e) {
|
|
54
|
+
if (typeof e === 'number')
|
|
55
|
+
e = new ApiError(const_1.HTTP_NOT_FOUND);
|
|
52
56
|
res = e;
|
|
53
57
|
}
|
|
54
58
|
if (isAsyncGenerator(res))
|
package/src/const.js
CHANGED
|
@@ -45,7 +45,7 @@ exports.DEV = process.env.DEV || exports.argv.dev ? 'DEV' : '';
|
|
|
45
45
|
exports.ORIGINAL_CWD = process.cwd();
|
|
46
46
|
exports.HFS_STARTED = new Date();
|
|
47
47
|
const PKG_PATH = (0, path_1.join)(__dirname, '..', 'package.json');
|
|
48
|
-
exports.BUILD_TIMESTAMP = "2024-02-
|
|
48
|
+
exports.BUILD_TIMESTAMP = "2024-02-11T10:59:36.071Z";
|
|
49
49
|
const pkg = JSON.parse(fs.readFileSync(PKG_PATH, 'utf8'));
|
|
50
50
|
exports.VERSION = pkg.version;
|
|
51
51
|
exports.RUNNING_BETA = exports.VERSION.includes('-');
|
package/src/cross.js
CHANGED
|
@@ -18,7 +18,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
20
|
exports.typedEntries = exports.typedKeys = exports.objRenameKey = exports.randomId = exports.getOrSet = exports.waitFor = exports.newObj = exports.findDefined = exports.isOrderedEqual = exports.swap = exports.tryJson = exports.dirname = exports.basename = exports.pendingPromise = exports._dbg = exports._log = exports.wantArray = exports.formatPerc = exports.with_ = exports.try_ = exports.setHidden = exports.onlyTruthy = exports.truthy = exports.splitAt = exports.strinsert = exports.removeStarting = exports.enforceFinal = exports.objSameKeys = exports.haveTimeout = exports.wait = exports.prefix = exports.formatSpeed = exports.formatBytes = exports.isWhoObject = exports.PERM_KEYS = exports.defaultPerms = exports.WHO_ANY_ACCOUNT = exports.WHO_NO_ONE = exports.WHO_ANYONE = exports.LIST = exports.CFG = exports.THEME_OPTIONS = exports.SORT_BY_OPTIONS = exports.FRONTEND_OPTIONS = exports.MAX_TILE_SIZE = exports.DAY = exports.HOUR = exports.MINUTE = exports.WIKI_URL = exports.REPO_URL = void 0;
|
|
21
|
-
exports.shortenAgent = exports.replace = exports.matches = exports.makeMatcher = exports.runAt = exports.pathEncode = exports.promiseBestEffort = exports.escapeHTML = exports.ipForUrl = exports.isIpLan = exports.isIpLocalHost = exports.xlate = exports.isEqualLax = exports.isWindowsDrive = exports.isIP = exports.isPrimitive = exports.formatTimestamp = exports.repeat = exports.asyncGeneratorToArray = exports.filterMapGenerator = exports.throw_ = exports.hasProp = void 0;
|
|
21
|
+
exports.shortenAgent = exports.inCommon = exports.replace = exports.matches = exports.makeMatcher = exports.runAt = exports.pathEncode = exports.promiseBestEffort = exports.escapeHTML = exports.ipForUrl = exports.isIpLan = exports.isIpLocalHost = exports.xlate = exports.isEqualLax = exports.isWindowsDrive = exports.isIP = exports.isPrimitive = exports.formatTimestamp = exports.repeat = exports.asyncGeneratorToArray = exports.filterMapGenerator = exports.throw_ = exports.hasProp = void 0;
|
|
22
22
|
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
23
23
|
// all content here is shared between client and server
|
|
24
24
|
const lodash_1 = __importDefault(require("lodash"));
|
|
@@ -405,6 +405,14 @@ function replace(s, symbols, delimiter = '') {
|
|
|
405
405
|
return s;
|
|
406
406
|
}
|
|
407
407
|
exports.replace = replace;
|
|
408
|
+
function inCommon(a, b) {
|
|
409
|
+
let i = 0;
|
|
410
|
+
const n = a.length;
|
|
411
|
+
while (i < n && a[i] === b[i])
|
|
412
|
+
i++;
|
|
413
|
+
return i;
|
|
414
|
+
}
|
|
415
|
+
exports.inCommon = inCommon;
|
|
408
416
|
function shortenAgent(agent) {
|
|
409
417
|
var _a;
|
|
410
418
|
return lodash_1.default.findKey(BROWSERS, re => re.test(agent))
|
package/src/errorPages.js
CHANGED
|
@@ -10,7 +10,7 @@ function getErrorSections() {
|
|
|
10
10
|
}
|
|
11
11
|
exports.getErrorSections = getErrorSections;
|
|
12
12
|
// to be used with errors whose recipient is possibly human
|
|
13
|
-
async function sendErrorPage(ctx, code) {
|
|
13
|
+
async function sendErrorPage(ctx, code = ctx.status) {
|
|
14
14
|
var _a, _b;
|
|
15
15
|
ctx.type = 'text';
|
|
16
16
|
ctx.set('content-disposition', ''); // reset ctx.attachment
|
|
@@ -23,7 +23,7 @@ async function sendErrorPage(ctx, code) {
|
|
|
23
23
|
return;
|
|
24
24
|
const trans = (_a = Object.values(lang)[0]) === null || _a === void 0 ? void 0 : _a.translate;
|
|
25
25
|
ctx.body = (_b = trans === null || trans === void 0 ? void 0 : trans[msg]) !== null && _b !== void 0 ? _b : msg;
|
|
26
|
-
const errorPage = (0, customHtml_1.getSection)(String(ctx.status));
|
|
26
|
+
const errorPage = (0, customHtml_1.getSection)(ctx.status === cross_1.HTTP_UNAUTHORIZED ? 'unauthorized' : String(ctx.status));
|
|
27
27
|
if (!errorPage)
|
|
28
28
|
return;
|
|
29
29
|
if (errorPage.includes('<'))
|
package/src/frontEndApis.js
CHANGED
|
@@ -148,9 +148,15 @@ exports.frontEndApis = {
|
|
|
148
148
|
const srcNode = await (0, vfs_1.urlToNode)(src, ctx);
|
|
149
149
|
if (!srcNode)
|
|
150
150
|
return const_1.HTTP_NOT_FOUND;
|
|
151
|
+
const s = srcNode.source;
|
|
152
|
+
const d = (0, path_1.join)(destNode.source, (0, path_1.basename)(srcNode.source));
|
|
151
153
|
return (0, vfs_1.statusCodeForMissingPerm)(srcNode, 'can_delete', ctx)
|
|
152
|
-
|| (0, promises_1.rename)(
|
|
153
|
-
|
|
154
|
+
|| (0, promises_1.rename)(s, d).catch(async (e) => {
|
|
155
|
+
if (e.code !== 'EXDEV')
|
|
156
|
+
throw e; // exdev = different drive
|
|
157
|
+
await (0, promises_1.copyFile)(s, d);
|
|
158
|
+
await (0, promises_1.unlink)(s);
|
|
159
|
+
}).catch(e => e.code || String(e));
|
|
154
160
|
}))
|
|
155
161
|
};
|
|
156
162
|
},
|
|
@@ -140,6 +140,7 @@
|
|
|
140
140
|
"go_last": "Vai alla fine",
|
|
141
141
|
"Shuffle": "Riproduzione casuale",
|
|
142
142
|
"Repeat": "Ripeti a fine lista",
|
|
143
|
-
"showHelpListShortcut": "Dalla lista dei file, clicca tenendo {key} per accedere velocemente al File Show"
|
|
143
|
+
"showHelpListShortcut": "Dalla lista dei file, clicca tenendo {key} per accedere velocemente al File Show",
|
|
144
|
+
"Invalid value": "Valore non valido"
|
|
144
145
|
}
|
|
145
146
|
}
|
package/src/misc.js
CHANGED
|
@@ -20,7 +20,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
exports.apiAssertTypes = exports.AsapStream = exports.asyncGeneratorToReadable = exports.same = exports.makeNetMatcher = exports.isLocalHost = exports.onOff = exports.pattern2filter = exports.onFirstEvent = exports.onProcessExit = void 0;
|
|
22
22
|
const path_1 = require("path");
|
|
23
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
24
23
|
const assert_1 = __importDefault(require("assert"));
|
|
25
24
|
__exportStar(require("./util-http"), exports);
|
|
26
25
|
__exportStar(require("./util-files"), exports);
|
|
@@ -51,8 +50,8 @@ function onFirstEvent(emitter, events, cb) {
|
|
|
51
50
|
}
|
|
52
51
|
exports.onFirstEvent = onFirstEvent;
|
|
53
52
|
function pattern2filter(pattern) {
|
|
54
|
-
const
|
|
55
|
-
return (s) => !s || !pattern ||
|
|
53
|
+
const matcher = (0, cross_1.makeMatcher)(pattern.includes('*') ? pattern : `*${pattern}*`); // if you specify *, we'll respect its position
|
|
54
|
+
return (s) => !s || !pattern || matcher((0, path_1.basename)(s));
|
|
56
55
|
}
|
|
57
56
|
exports.pattern2filter = pattern2filter;
|
|
58
57
|
// install multiple handlers and returns a handy 'uninstall' function which requires no parameter. Pass a map {event:handler}
|
package/src/nat.js
CHANGED
|
@@ -66,12 +66,13 @@ exports.getPublicIps = (0, debounceAsync_1.debounceAsync)(async () => {
|
|
|
66
66
|
exports.getNatInfo = (0, debounceAsync_1.debounceAsync)(async () => {
|
|
67
67
|
var _a, _b, _c, _d;
|
|
68
68
|
const gettingIps = (0, exports.getPublicIps)(); // don't wait, do it in parallel
|
|
69
|
-
const res = await exports.upnpClient.getGateway().catch(() => null);
|
|
69
|
+
const res = await (0, cross_1.haveTimeout)(10000, exports.upnpClient.getGateway()).catch(() => null);
|
|
70
70
|
const status = await (0, listen_1.getServerStatus)();
|
|
71
71
|
const mappings = res && await (0, cross_1.haveTimeout)(5000, exports.upnpClient.getMappings()).catch(() => null);
|
|
72
72
|
console.debug('mappings found', mappings === null || mappings === void 0 ? void 0 : mappings.map(x => x.description));
|
|
73
73
|
const gatewayIp = res ? new URL(res.gateway.description).hostname : await findGateway().catch(() => undefined);
|
|
74
|
-
const
|
|
74
|
+
const localIps = await (0, listen_1.getIps)(false);
|
|
75
|
+
const localIp = (res === null || res === void 0 ? void 0 : res.address) || gatewayIp ? lodash_1.default.maxBy(localIps, x => (0, cross_1.inCommon)(x, gatewayIp)) : localIps[0];
|
|
75
76
|
const internalPort = ((_a = status === null || status === void 0 ? void 0 : status.https) === null || _a === void 0 ? void 0 : _a.listening) && status.https.port || ((_b = status === null || status === void 0 ? void 0 : status.http) === null || _b === void 0 ? void 0 : _b.listening) && status.http.port || undefined;
|
|
76
77
|
const mapped = lodash_1.default.find(mappings, x => x.private.host === localIp && x.private.port === internalPort);
|
|
77
78
|
const externalPort = mapped === null || mapped === void 0 ? void 0 : mapped.public.port;
|
package/src/serveFile.js
CHANGED
|
@@ -122,7 +122,7 @@ function applyRange(ctx, totalSize = ctx.response.length) {
|
|
|
122
122
|
return ctx.throw(const_1.HTTP_BAD_REQUEST, 'bad range');
|
|
123
123
|
const max = totalSize - 1;
|
|
124
124
|
const start = bytes[0] ? Number(bytes[0]) : Math.max(0, totalSize - Number(bytes[1])); // a negative start is relative to the end
|
|
125
|
-
const end = bytes[0] ? Number(bytes[1]
|
|
125
|
+
const end = (bytes[0] && bytes[1]) ? Math.min(max, Number(bytes[1])) : max;
|
|
126
126
|
// we don't support last-bytes without knowing max
|
|
127
127
|
if (isNaN(end) && isNaN(max) || end > max || start > max) {
|
|
128
128
|
ctx.status = const_1.HTTP_RANGE_NOT_SATISFIABLE;
|
|
@@ -88,7 +88,7 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
|
|
|
88
88
|
return !node.source ? (0, errorPages_1.sendErrorPage)(ctx, cross_const_1.HTTP_METHOD_NOT_ALLOWED)
|
|
89
89
|
: !(0, vfs_1.statusCodeForMissingPerm)(node, 'can_read', ctx) ? (0, serveFile_1.serveFileNode)(ctx, node)
|
|
90
90
|
: ctx.status !== cross_const_1.HTTP_UNAUTHORIZED ? null
|
|
91
|
-
: !path.endsWith('/') ? ctx.set('WWW-Authenticate', 'Basic') // this is necessary to support standard urls with credentials. Final / means we are dealing with default file...
|
|
91
|
+
: !path.endsWith('/') ? (ctx.set('WWW-Authenticate', 'Basic'), (0, errorPages_1.sendErrorPage)(ctx)) // this is necessary to support standard urls with credentials. Final / means we are dealing with default file...
|
|
92
92
|
: (ctx.state.serveApp = true) && serveFrontendFiles(ctx, next); // ...for which we still provide fancy login
|
|
93
93
|
if (!path.endsWith('/'))
|
|
94
94
|
return ctx.redirect(ctx.state.revProxyPath + ctx.originalUrl.replace(/(\?|$)/, '/$1')); // keep query-string, if any
|