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/apiMiddleware.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
|
};
|
|
@@ -24,11 +24,11 @@ function apiMiddleware(apis) {
|
|
|
24
24
|
console.debug('API', ctx.method, ctx.path, { ...params });
|
|
25
25
|
if (!apis.hasOwnProperty(ctx.path)) {
|
|
26
26
|
ctx.body = 'invalid api';
|
|
27
|
-
return ctx.status =
|
|
27
|
+
return ctx.status = const_1.HTTP_NOT_FOUND;
|
|
28
28
|
}
|
|
29
29
|
const csrf = ctx.cookies.get('csrf');
|
|
30
30
|
// we don't rely on SameSite cookie option because it's https-only
|
|
31
|
-
let res = csrf && csrf !== params.csrf ? new ApiError(const_1.
|
|
31
|
+
let res = csrf && csrf !== params.csrf ? new ApiError(const_1.HTTP_UNAUTHORIZED, 'csrf')
|
|
32
32
|
: await apis[ctx.path](params || {}, ctx);
|
|
33
33
|
if (isAsyncGenerator(res))
|
|
34
34
|
res = (0, misc_1.asyncGeneratorToReadable)(res);
|
|
@@ -45,7 +45,7 @@ function apiMiddleware(apis) {
|
|
|
45
45
|
}
|
|
46
46
|
if (res instanceof Error) { // generic exception
|
|
47
47
|
ctx.body = String(res);
|
|
48
|
-
return ctx.status =
|
|
48
|
+
return ctx.status = const_1.HTTP_BAD_REQUEST;
|
|
49
49
|
}
|
|
50
50
|
ctx.body = res;
|
|
51
51
|
};
|
|
@@ -95,6 +95,9 @@ class SendListReadable extends stream_1.Readable {
|
|
|
95
95
|
custom(data) {
|
|
96
96
|
this._push(data);
|
|
97
97
|
}
|
|
98
|
+
props(props) {
|
|
99
|
+
this._push({ props });
|
|
100
|
+
}
|
|
98
101
|
error(msg, close = false) {
|
|
99
102
|
this._push({ error: msg });
|
|
100
103
|
this.lastError = msg;
|
package/src/block.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
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
5
|
};
|
package/src/commands.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
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
5
|
};
|
package/src/config.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/connections.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/const.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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
4
|
if (k2 === undefined) k2 = k;
|
|
5
5
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -27,7 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
28
28
|
};
|
|
29
29
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
-
exports.APP_PATH = exports.IS_WINDOWS = exports.
|
|
30
|
+
exports.APP_PATH = exports.IS_WINDOWS = exports.HTTP_SERVER_ERROR = exports.HTTP_FOOL = exports.HTTP_RANGE_NOT_SATISFIABLE = exports.HTTP_CONFLICT = exports.HTTP_NOT_ACCEPTABLE = exports.HTTP_METHOD_NOT_ALLOWED = exports.HTTP_NOT_FOUND = exports.HTTP_FORBIDDEN = exports.HTTP_UNAUTHORIZED = exports.HTTP_BAD_REQUEST = exports.HTTP_NOT_MODIFIED = exports.HTTP_TEMPORARY_REDIRECT = exports.HTTP_PARTIAL_CONTENT = exports.HTTP_NO_CONTENT = exports.HTTP_OK = exports.PLUGINS_PUB_URI = exports.API_URI = exports.ADMIN_URI = exports.FRONTEND_URI = exports.SPECIAL_URI = exports.COMPATIBLE_API_VERSION = exports.API_VERSION = exports.SESSION_DURATION = exports.DAY = exports.VERSION = exports.BUILD_TIMESTAMP = exports.HFS_STARTED = exports.ORIGINAL_CWD = exports.DEV = exports.argv = void 0;
|
|
31
31
|
const minimist_1 = __importDefault(require("minimist"));
|
|
32
32
|
const fs = __importStar(require("fs"));
|
|
33
33
|
const os_1 = require("os");
|
|
@@ -50,10 +50,21 @@ exports.FRONTEND_URI = exports.SPECIAL_URI + 'frontend/';
|
|
|
50
50
|
exports.ADMIN_URI = exports.SPECIAL_URI + 'admin/';
|
|
51
51
|
exports.API_URI = exports.SPECIAL_URI + 'api/';
|
|
52
52
|
exports.PLUGINS_PUB_URI = exports.SPECIAL_URI + 'plugins/';
|
|
53
|
-
exports.
|
|
54
|
-
exports.
|
|
55
|
-
exports.
|
|
56
|
-
exports.
|
|
53
|
+
exports.HTTP_OK = 200;
|
|
54
|
+
exports.HTTP_NO_CONTENT = 204;
|
|
55
|
+
exports.HTTP_PARTIAL_CONTENT = 206;
|
|
56
|
+
exports.HTTP_TEMPORARY_REDIRECT = 302;
|
|
57
|
+
exports.HTTP_NOT_MODIFIED = 304;
|
|
58
|
+
exports.HTTP_BAD_REQUEST = 400;
|
|
59
|
+
exports.HTTP_UNAUTHORIZED = 401;
|
|
60
|
+
exports.HTTP_FORBIDDEN = 403;
|
|
61
|
+
exports.HTTP_NOT_FOUND = 404;
|
|
62
|
+
exports.HTTP_METHOD_NOT_ALLOWED = 405;
|
|
63
|
+
exports.HTTP_NOT_ACCEPTABLE = 406;
|
|
64
|
+
exports.HTTP_CONFLICT = 409;
|
|
65
|
+
exports.HTTP_RANGE_NOT_SATISFIABLE = 416;
|
|
66
|
+
exports.HTTP_FOOL = 418;
|
|
67
|
+
exports.HTTP_SERVER_ERROR = 500;
|
|
57
68
|
exports.IS_WINDOWS = process.platform === 'win32';
|
|
58
69
|
const IS_BINARY = !(0, path_1.basename)(process.argv0).includes('node'); // this won't be node if pkg was used
|
|
59
70
|
exports.APP_PATH = (0, path_1.dirname)(IS_BINARY ? process.argv0 : __dirname);
|
|
@@ -62,7 +73,7 @@ if (exports.DEV)
|
|
|
62
73
|
console.clear();
|
|
63
74
|
else
|
|
64
75
|
console.debug = () => { };
|
|
65
|
-
console.log(`HFS ~ HTTP File Server - Copyright 2021-
|
|
76
|
+
console.log(`HFS ~ HTTP File Server - Copyright 2021-2023, Massimo Melina <a@rejetto.com>`);
|
|
66
77
|
console.log(`License https://www.gnu.org/licenses/gpl-3.0.txt`);
|
|
67
78
|
console.log('started', exports.HFS_STARTED.toLocaleString(), exports.DEV);
|
|
68
79
|
console.log('version', exports.VERSION || '-');
|
package/src/crypt.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/debounceAsync.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
|
// like lodash.debounce, but also avoids async invocations to overlap
|
|
4
5
|
function debounceAsync(callback, wait = 100, { leading = false, maxWait = Infinity } = {}) {
|
package/src/events.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/frontEndApis.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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
4
|
if (k2 === undefined) k2 = k;
|
|
5
5
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
package/src/github.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
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
5
|
};
|
|
@@ -9,6 +10,7 @@ const misc_1 = require("./misc");
|
|
|
9
10
|
const plugins_1 = require("./plugins");
|
|
10
11
|
const apiMiddleware_1 = require("./apiMiddleware");
|
|
11
12
|
const lodash_1 = __importDefault(require("lodash"));
|
|
13
|
+
const const_1 = require("./const");
|
|
12
14
|
const DIST_ROOT = 'dist/';
|
|
13
15
|
const downloading = {};
|
|
14
16
|
function downloadProgress(id, status) {
|
|
@@ -20,7 +22,7 @@ function downloadProgress(id, status) {
|
|
|
20
22
|
}
|
|
21
23
|
async function downloadPlugin(repo, branch = '', overwrite) {
|
|
22
24
|
if (downloading[repo])
|
|
23
|
-
return new apiMiddleware_1.ApiError(
|
|
25
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_CONFLICT, "already downloading");
|
|
24
26
|
downloadProgress(repo, true);
|
|
25
27
|
const rec = await getRepoInfo(repo);
|
|
26
28
|
if (!branch)
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
-
// This file is part of HFS - Copyright 2021-
|
|
3
|
+
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
4
4
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
5
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
6
|
};
|
|
@@ -42,7 +42,8 @@ function errorHandler(err) {
|
|
|
42
42
|
const { code } = err;
|
|
43
43
|
if (const_1.DEV && code === 'ENOENT' && err.path.endsWith('sockjs-node'))
|
|
44
44
|
return; // spam out dev stuff
|
|
45
|
-
if (code === 'ECANCELED' || code === 'ECONNRESET' || code === 'ECONNABORTED' || code === 'EPIPE'
|
|
45
|
+
if (code === 'ECANCELED' || code === 'ECONNRESET' || code === 'ECONNABORTED' || code === 'EPIPE'
|
|
46
|
+
|| code === 'HPE_INVALID_EOF_STATE')
|
|
46
47
|
return; // someone interrupted, don't care
|
|
47
48
|
console.error('server error', err);
|
|
48
49
|
}
|
package/src/listen.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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
4
|
if (k2 === undefined) k2 = k;
|
|
5
5
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
package/src/log.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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
4
|
if (k2 === undefined) k2 = k;
|
|
5
5
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -35,7 +35,7 @@ const promises_1 = require("fs/promises");
|
|
|
35
35
|
const const_1 = require("./const");
|
|
36
36
|
const events_1 = __importDefault(require("./events"));
|
|
37
37
|
const lodash_1 = __importDefault(require("lodash"));
|
|
38
|
-
const
|
|
38
|
+
const util_files_1 = require("./util-files");
|
|
39
39
|
const perm_1 = require("./perm");
|
|
40
40
|
class Logger {
|
|
41
41
|
constructor(name) {
|
|
@@ -54,8 +54,8 @@ class Logger {
|
|
|
54
54
|
this.last = stats.mtime || stats.ctime;
|
|
55
55
|
}
|
|
56
56
|
catch (_b) {
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
if (await (0, util_files_1.prepareFolder)(path) === false)
|
|
58
|
+
console.log("cannot create folder for", path);
|
|
59
59
|
}
|
|
60
60
|
this.reopen();
|
|
61
61
|
}
|
package/src/middlewares.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
|
};
|
|
@@ -22,6 +22,9 @@ const connections_1 = require("./connections");
|
|
|
22
22
|
const basic_auth_1 = __importDefault(require("basic-auth"));
|
|
23
23
|
const tssrp6a_1 = require("tssrp6a");
|
|
24
24
|
const api_auth_1 = require("./api.auth");
|
|
25
|
+
const path_1 = require("path");
|
|
26
|
+
const fs_1 = require("fs");
|
|
27
|
+
const promises_1 = require("stream/promises");
|
|
25
28
|
exports.gzipper = (0, koa_compress_1.default)({
|
|
26
29
|
threshold: 2048,
|
|
27
30
|
gzip: { flush: require('zlib').constants.Z_SYNC_FLUSH },
|
|
@@ -66,9 +69,17 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
|
|
|
66
69
|
return ctx.redirect(const_1.ADMIN_URI);
|
|
67
70
|
if (path.startsWith(const_1.ADMIN_URI))
|
|
68
71
|
return serveAdminPrefixed(ctx, next);
|
|
72
|
+
if (ctx.method === 'PUT') { // curl -T file url/
|
|
73
|
+
const decPath = decodeURI(path);
|
|
74
|
+
let rest = (0, path_1.basename)(decPath);
|
|
75
|
+
const folder = await (0, vfs_1.urlToNode)((0, path_1.dirname)(decPath), ctx, vfs_1.vfs, v => rest = v + '/' + rest);
|
|
76
|
+
if (!folder)
|
|
77
|
+
return ctx.status = const_1.HTTP_NOT_FOUND;
|
|
78
|
+
return await receiveUpload(folder, rest, ctx.req, ctx);
|
|
79
|
+
}
|
|
69
80
|
const node = await (0, vfs_1.urlToNode)(path, ctx);
|
|
70
81
|
if (!node)
|
|
71
|
-
return ctx.status =
|
|
82
|
+
return ctx.status = const_1.HTTP_NOT_FOUND;
|
|
72
83
|
const canRead = (0, vfs_1.hasPermission)(node, 'can_read', ctx);
|
|
73
84
|
const isFolder = await (0, vfs_1.nodeIsDirectory)(node);
|
|
74
85
|
if (isFolder && !path.endsWith('/'))
|
|
@@ -78,7 +89,7 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
|
|
|
78
89
|
: next();
|
|
79
90
|
if (!canRead) {
|
|
80
91
|
ctx.status = (0, vfs_1.cantReadStatusCode)(node);
|
|
81
|
-
if (ctx.status === const_1.
|
|
92
|
+
if (ctx.status === const_1.HTTP_FORBIDDEN)
|
|
82
93
|
return;
|
|
83
94
|
const browserDetected = ctx.get('Upgrade-Insecure-Requests') || ctx.get('Sec-Fetch-Mode'); // ugh, heuristics
|
|
84
95
|
if (!browserDetected) // we don't want to trigger basic authentication on browsers, it's meant for download managers only
|
|
@@ -99,6 +110,15 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
|
|
|
99
110
|
return serveFrontendFiles(ctx, next);
|
|
100
111
|
};
|
|
101
112
|
exports.serveGuiAndSharedFiles = serveGuiAndSharedFiles;
|
|
113
|
+
async function receiveUpload(base, path, stream, ctx) {
|
|
114
|
+
if (!base.source || !(0, vfs_1.hasPermission)(base, 'can_upload', ctx))
|
|
115
|
+
return ctx.status = base.can_upload === false ? const_1.HTTP_FORBIDDEN : const_1.HTTP_UNAUTHORIZED;
|
|
116
|
+
path = (0, path_1.join)(base.source, path);
|
|
117
|
+
await (0, misc_1.prepareFolder)(path);
|
|
118
|
+
const dest = (0, fs_1.createWriteStream)(path);
|
|
119
|
+
await (0, promises_1.pipeline)(stream, dest);
|
|
120
|
+
ctx.body = '{}';
|
|
121
|
+
}
|
|
102
122
|
let proxyDetected = false;
|
|
103
123
|
const someSecurity = async (ctx, next) => {
|
|
104
124
|
ctx.request.ip = (0, connections_1.normalizeIp)(ctx.ip);
|
|
@@ -108,14 +128,14 @@ const someSecurity = async (ctx, next) => {
|
|
|
108
128
|
if (const_1.DEV && proxy && [process.env.FRONTEND_PROXY, process.env.ADMIN_PROXY].includes(ctx.get('X-Forwarded-port')))
|
|
109
129
|
proxy = '';
|
|
110
130
|
if ((0, misc_1.dirTraversal)(decodeURI(ctx.path)))
|
|
111
|
-
return ctx.status =
|
|
131
|
+
return ctx.status = const_1.HTTP_FOOL;
|
|
112
132
|
if ((0, block_1.applyBlock)(ctx.socket, ctx.ip))
|
|
113
133
|
return;
|
|
114
134
|
proxyDetected || (proxyDetected = proxy > '');
|
|
115
135
|
ctx.state.proxiedFor = proxy;
|
|
116
136
|
}
|
|
117
137
|
catch (_a) {
|
|
118
|
-
return ctx.status =
|
|
138
|
+
return ctx.status = const_1.HTTP_FOOL;
|
|
119
139
|
}
|
|
120
140
|
return next();
|
|
121
141
|
};
|
|
@@ -153,17 +173,17 @@ async function srpCheck(username, password) {
|
|
|
153
173
|
}
|
|
154
174
|
// unify get/post parameters, with JSON decoding to not be limited to strings
|
|
155
175
|
const paramsDecoder = async (ctx, next) => {
|
|
156
|
-
ctx.params = ctx.method === 'POST' ? (0, misc_1.tryJson)(await
|
|
176
|
+
ctx.params = ctx.method === 'POST' ? (0, misc_1.tryJson)(await stream2string(ctx.req))
|
|
157
177
|
: (0, misc_1.objSameKeys)(ctx.query, x => Array.isArray(x) ? x : (0, misc_1.tryJson)(x));
|
|
158
178
|
await next();
|
|
159
179
|
};
|
|
160
180
|
exports.paramsDecoder = paramsDecoder;
|
|
161
|
-
async function
|
|
181
|
+
async function stream2string(stream) {
|
|
162
182
|
return new Promise((resolve, reject) => {
|
|
163
183
|
let data = '';
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
184
|
+
stream.on('data', chunk => data += chunk);
|
|
185
|
+
stream.on('error', reject);
|
|
186
|
+
stream.on('end', () => {
|
|
167
187
|
try {
|
|
168
188
|
resolve(data);
|
|
169
189
|
}
|
package/src/misc.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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
4
|
if (k2 === undefined) k2 = k;
|
|
5
5
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
package/src/perm.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.anyAccountCanLoginAdmin = exports.accountCanLoginAdmin = exports.accountCanLogin = exports.accountHasPassword = exports.getFromAccount = exports.delAccount = exports.setAccount = exports.addAccount = exports.renameAccount = exports.normalizeUsername = exports.updateAccount = exports.allowClearTextLogin = exports.saveSrpInfo = exports.getAccount = exports.getCurrentUsernameExpanded = exports.getCurrentUsername =
|
|
7
|
+
exports.anyAccountCanLoginAdmin = exports.accountCanLoginAdmin = exports.accountCanLogin = exports.accountHasPassword = exports.getFromAccount = exports.delAccount = exports.setAccount = exports.addAccount = exports.renameAccount = exports.normalizeUsername = exports.accountsConfig = exports.updateAccount = exports.allowClearTextLogin = exports.saveSrpInfo = exports.getAccount = exports.getCurrentUsernameExpanded = exports.getCurrentUsername = void 0;
|
|
8
8
|
const lodash_1 = __importDefault(require("lodash"));
|
|
9
9
|
const crypt_1 = require("./crypt");
|
|
10
10
|
const misc_1 = require("./misc");
|
|
@@ -12,10 +12,6 @@ const config_1 = require("./config");
|
|
|
12
12
|
const tssrp6a_1 = require("tssrp6a");
|
|
13
13
|
const events_1 = __importDefault(require("./events"));
|
|
14
14
|
let accounts = {};
|
|
15
|
-
function getAccounts() {
|
|
16
|
-
return accounts;
|
|
17
|
-
}
|
|
18
|
-
exports.getAccounts = getAccounts;
|
|
19
15
|
function getCurrentUsername(ctx) {
|
|
20
16
|
var _a;
|
|
21
17
|
return ((_a = ctx.state.account) === null || _a === void 0 ? void 0 : _a.username) || '';
|
|
@@ -63,27 +59,34 @@ async function updateAccount(account, changer) {
|
|
|
63
59
|
console.log('please reset password for account', username);
|
|
64
60
|
process.exit(1);
|
|
65
61
|
}
|
|
66
|
-
if (account.belongs)
|
|
67
|
-
account.belongs = (0, misc_1.wantArray)(account.belongs)
|
|
68
|
-
|
|
62
|
+
if (account.belongs) {
|
|
63
|
+
account.belongs = (0, misc_1.wantArray)(account.belongs);
|
|
64
|
+
lodash_1.default.remove(account.belongs, b => {
|
|
65
|
+
if (b in accounts)
|
|
66
|
+
return;
|
|
67
|
+
console.error(`account ${username} belongs to non-existing ${b}`);
|
|
68
|
+
return true;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
69
71
|
if (was !== JSON.stringify(account))
|
|
70
72
|
saveAccountsAsap();
|
|
71
73
|
}
|
|
72
74
|
exports.updateAccount = updateAccount;
|
|
73
|
-
const saveAccountsAsap = config_1.saveConfigAsap;
|
|
74
|
-
|
|
75
|
-
accountsConfig.sub(
|
|
76
|
-
//
|
|
77
|
-
accounts =
|
|
78
|
-
await Promise.all(lodash_1.default.map(accounts, async (rec, k) => {
|
|
75
|
+
const saveAccountsAsap = () => { (0, config_1.saveConfigAsap)().then(); };
|
|
76
|
+
exports.accountsConfig = (0, config_1.defineConfig)('accounts', {});
|
|
77
|
+
exports.accountsConfig.sub(obj => {
|
|
78
|
+
// consider some validation here
|
|
79
|
+
lodash_1.default.each(accounts = obj, (rec, k) => {
|
|
79
80
|
const norm = normalizeUsername(k);
|
|
80
|
-
if (
|
|
81
|
-
rec
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
if ((rec === null || rec === void 0 ? void 0 : rec.username) !== norm) {
|
|
82
|
+
if (!rec) // an empty object in yaml is parsed as null
|
|
83
|
+
rec = obj[norm] = { username: norm };
|
|
84
|
+
else if ((0, misc_1.objRenameKey)(obj, k, norm))
|
|
85
|
+
saveAccountsAsap();
|
|
86
|
+
(0, misc_1.setHidden)(rec, { username: norm });
|
|
87
|
+
}
|
|
88
|
+
updateAccount(rec).then(); // work password fields
|
|
89
|
+
});
|
|
87
90
|
});
|
|
88
91
|
function normalizeUsername(username) {
|
|
89
92
|
return username.toLocaleLowerCase();
|
|
@@ -120,8 +123,7 @@ function addAccount(username, props) {
|
|
|
120
123
|
return;
|
|
121
124
|
const filteredProps = lodash_1.default.pickBy(lodash_1.default.pick(props, assignableProps), Boolean);
|
|
122
125
|
const copy = (0, misc_1.setHidden)(filteredProps, { username }); // have the field in the object but hidden so that stringification won't include it
|
|
123
|
-
accountsConfig.set(accounts => Object.assign(accounts, { [username]: copy }));
|
|
124
|
-
saveAccountsAsap().then();
|
|
126
|
+
exports.accountsConfig.set(accounts => Object.assign(accounts, { [username]: copy }));
|
|
125
127
|
return copy;
|
|
126
128
|
}
|
|
127
129
|
exports.addAccount = addAccount;
|
|
@@ -136,15 +138,15 @@ function setAccount(username, changes) {
|
|
|
136
138
|
Object.assign(acc, rest);
|
|
137
139
|
if (changes.username)
|
|
138
140
|
renameAccount(username, changes.username);
|
|
139
|
-
saveAccountsAsap()
|
|
141
|
+
saveAccountsAsap();
|
|
140
142
|
return acc;
|
|
141
143
|
}
|
|
142
144
|
exports.setAccount = setAccount;
|
|
143
145
|
function delAccount(username) {
|
|
144
146
|
if (!getAccount(username))
|
|
145
147
|
return false;
|
|
146
|
-
accountsConfig.set(accounts => Object.assign(accounts, { [normalizeUsername(username)]: undefined }));
|
|
147
|
-
saveAccountsAsap()
|
|
148
|
+
exports.accountsConfig.set(accounts => Object.assign(accounts, { [normalizeUsername(username)]: undefined }));
|
|
149
|
+
saveAccountsAsap();
|
|
148
150
|
return true;
|
|
149
151
|
}
|
|
150
152
|
exports.delAccount = delAccount;
|
|
@@ -172,10 +174,10 @@ function accountCanLogin(account) {
|
|
|
172
174
|
}
|
|
173
175
|
exports.accountCanLogin = accountCanLogin;
|
|
174
176
|
function accountCanLoginAdmin(account) {
|
|
175
|
-
return accountCanLogin(account) && getFromAccount(account, a => a.admin);
|
|
177
|
+
return accountCanLogin(account) && Boolean(getFromAccount(account, a => a.admin));
|
|
176
178
|
}
|
|
177
179
|
exports.accountCanLoginAdmin = accountCanLoginAdmin;
|
|
178
180
|
function anyAccountCanLoginAdmin() {
|
|
179
|
-
return
|
|
181
|
+
return Boolean(lodash_1.default.find(exports.accountsConfig.get(), accountCanLoginAdmin));
|
|
180
182
|
}
|
|
181
183
|
exports.anyAccountCanLoginAdmin = anyAccountCanLoginAdmin;
|
package/src/plugins.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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
4
|
if (k2 === undefined) k2 = k;
|
|
5
5
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
package/src/serveFile.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
|
};
|
|
@@ -27,7 +27,7 @@ function serveFileNode(node) {
|
|
|
27
27
|
const ref = (_a = /\/\/([^:/]+)/.exec(ctx.get('referer'))) === null || _a === void 0 ? void 0 : _a[1]; // extract host from url
|
|
28
28
|
if (ref && ref !== host() // automatic accept if referer is basically the hosting domain
|
|
29
29
|
&& !(0, micromatch_1.isMatch)(ref, allowed))
|
|
30
|
-
return ctx.status = const_1.
|
|
30
|
+
return ctx.status = const_1.HTTP_FORBIDDEN;
|
|
31
31
|
function host() {
|
|
32
32
|
const s = ctx.get('host');
|
|
33
33
|
return s[0] === '[' ? s.slice(1, s.indexOf(']')) : s === null || s === void 0 ? void 0 : s.split(':')[0];
|
|
@@ -50,26 +50,26 @@ function serveFile(source, mime, content) {
|
|
|
50
50
|
if (mime)
|
|
51
51
|
ctx.type = mime;
|
|
52
52
|
if (ctx.method === 'OPTIONS') {
|
|
53
|
-
ctx.status = const_1.
|
|
53
|
+
ctx.status = const_1.HTTP_NO_CONTENT;
|
|
54
54
|
ctx.set({ Allow: 'OPTIONS, GET, HEAD' });
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
if (ctx.method !== 'GET')
|
|
58
|
-
return ctx.status = const_1.
|
|
58
|
+
return ctx.status = const_1.HTTP_METHOD_NOT_ALLOWED;
|
|
59
59
|
try {
|
|
60
60
|
const stats = await (0, util_1.promisify)(fs_1.stat)(source); // using fs's function instead of fs/promises, because only the former is supported by pkg
|
|
61
61
|
ctx.set('Last-Modified', stats.mtime.toUTCString());
|
|
62
62
|
ctx.fileSource = source;
|
|
63
|
-
ctx.status =
|
|
63
|
+
ctx.status = const_1.HTTP_OK;
|
|
64
64
|
if (ctx.fresh)
|
|
65
|
-
return ctx.status =
|
|
65
|
+
return ctx.status = const_1.HTTP_NOT_MODIFIED;
|
|
66
66
|
if (content !== undefined)
|
|
67
67
|
return ctx.body = content;
|
|
68
68
|
const range = getRange(ctx, stats.size);
|
|
69
69
|
ctx.body = (0, fs_1.createReadStream)(source, range);
|
|
70
70
|
}
|
|
71
71
|
catch (_a) {
|
|
72
|
-
return ctx.status =
|
|
72
|
+
return ctx.status = const_1.HTTP_NOT_FOUND;
|
|
73
73
|
}
|
|
74
74
|
};
|
|
75
75
|
}
|
|
@@ -83,21 +83,21 @@ function getRange(ctx, totalSize) {
|
|
|
83
83
|
}
|
|
84
84
|
const ranges = range.split('=')[1];
|
|
85
85
|
if (ranges.includes(','))
|
|
86
|
-
return ctx.throw(
|
|
86
|
+
return ctx.throw(const_1.HTTP_BAD_REQUEST, 'multi-range not supported');
|
|
87
87
|
let bytes = ranges === null || ranges === void 0 ? void 0 : ranges.split('-');
|
|
88
88
|
if (!(bytes === null || bytes === void 0 ? void 0 : bytes.length))
|
|
89
|
-
return ctx.throw(
|
|
89
|
+
return ctx.throw(const_1.HTTP_BAD_REQUEST, 'bad range');
|
|
90
90
|
const max = totalSize - 1;
|
|
91
91
|
const start = bytes[0] ? Number(bytes[0]) : Math.max(0, totalSize - Number(bytes[1])); // a negative start is relative to the end
|
|
92
92
|
const end = bytes[0] ? Number(bytes[1] || max) : max;
|
|
93
93
|
// we don't support last-bytes without knowing max
|
|
94
94
|
if (isNaN(end) && isNaN(max) || end > max || start > max) {
|
|
95
|
-
ctx.status =
|
|
95
|
+
ctx.status = const_1.HTTP_RANGE_NOT_SATISFIABLE;
|
|
96
96
|
ctx.set('Content-Range', `bytes ${totalSize}`);
|
|
97
97
|
ctx.body = 'Requested Range Not Satisfiable';
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
|
-
ctx.status =
|
|
100
|
+
ctx.status = const_1.HTTP_PARTIAL_CONTENT;
|
|
101
101
|
ctx.set('Content-Range', `bytes ${start}-${isNaN(end) ? '' : end}/${isNaN(totalSize) ? '*' : totalSize}`);
|
|
102
102
|
ctx.response.length = end - start + 1;
|
|
103
103
|
return { start, end };
|
package/src/serveGuiFiles.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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
4
|
if (k2 === undefined) k2 = k;
|
|
5
5
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -43,12 +43,12 @@ function serveStatic(uri) {
|
|
|
43
43
|
const cache = {};
|
|
44
44
|
return async (ctx, next) => {
|
|
45
45
|
if (ctx.method === 'OPTIONS') {
|
|
46
|
-
ctx.status = const_1.
|
|
46
|
+
ctx.status = const_1.HTTP_NO_CONTENT;
|
|
47
47
|
ctx.set({ Allow: 'OPTIONS, GET' });
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
if (ctx.method !== 'GET')
|
|
51
|
-
return ctx.status = const_1.
|
|
51
|
+
return ctx.status = const_1.HTTP_METHOD_NOT_ALLOWED;
|
|
52
52
|
const serveApp = shouldServeApp(ctx);
|
|
53
53
|
const fullPath = (0, path_1.join)(__dirname, '..', DEV_STATIC, folder, serveApp ? '/index.html' : ctx.path);
|
|
54
54
|
const content = await (0, misc_1.getOrSet)(cache, ctx.path, async () => {
|
|
@@ -57,7 +57,7 @@ function serveStatic(uri) {
|
|
|
57
57
|
: adjustBundlerLinks(ctx.path, uri, data);
|
|
58
58
|
});
|
|
59
59
|
if (content === null)
|
|
60
|
-
return ctx.status =
|
|
60
|
+
return ctx.status = const_1.HTTP_NOT_FOUND;
|
|
61
61
|
if (!serveApp)
|
|
62
62
|
return (0, serveFile_1.serveFile)(fullPath, 'auto', content)(ctx, next);
|
|
63
63
|
// we don't cache the index as it's small and may prevent plugins change to apply
|
package/src/sse.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
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
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const stream_1 = require("stream");
|
|
5
|
+
const const_1 = require("./const");
|
|
5
6
|
function createSSE(ctx) {
|
|
6
7
|
const { socket } = ctx.req;
|
|
7
8
|
socket.setTimeout(0);
|
|
@@ -13,7 +14,7 @@ function createSSE(ctx) {
|
|
|
13
14
|
'Connection': 'keep-alive',
|
|
14
15
|
'X-Accel-Buffering': 'no', // avoid buffering when reverse-proxied through nginx
|
|
15
16
|
});
|
|
16
|
-
ctx.status =
|
|
17
|
+
ctx.status = const_1.HTTP_OK;
|
|
17
18
|
return ctx.body = new stream_1.Transform({
|
|
18
19
|
objectMode: true,
|
|
19
20
|
transform(chunk, encoding, cb) {
|
package/src/throttler.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/update.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.update = exports.getUpdate = void 0;
|
|
4
5
|
const github_1 = require("./github");
|