hfs 0.57.0-beta2 → 0.57.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-Cl7PJ7_4.js → index-wpTZkGgW.js} +118 -118
- package/admin/assets/{sha512-DwXzavpM.js → sha512-CpPcS3nM.js} +1 -1
- package/admin/index.html +1 -1
- package/frontend/assets/{index-legacy-0ZDBWQI9.js → index-legacy-vzFlSPl0.js} +6 -6
- package/frontend/assets/{sha512-legacy-slBG5k4n.js → sha512-legacy-K4Qp1SfQ.js} +1 -1
- package/frontend/index.html +1 -1
- package/package.json +2 -2
- package/src/adminApis.js +10 -2
- package/src/api.accounts.js +11 -7
- package/src/api.get_file_list.js +1 -1
- package/src/api.plugins.js +2 -4
- package/src/auth.js +1 -1
- package/src/block.js +5 -5
- package/src/const.js +5 -3
- package/src/cross-const.js +2 -1
- package/src/cross.js +14 -2
- package/src/frontEndApis.js +1 -0
- package/src/github.js +1 -1
- package/src/listen.js +4 -4
- package/src/middlewares.js +3 -7
- package/src/misc.js +43 -37
- package/src/perm.js +24 -25
- package/src/plugins.js +2 -2
- package/src/roots.js +2 -2
- package/src/serveFile.js +3 -2
- package/src/serveGuiAndSharedFiles.js +2 -2
- package/src/serveGuiFiles.js +20 -2
- package/src/util-http.js +1 -1
- package/src/vfs.js +3 -2
- package/src/zip.js +0 -1
package/src/perm.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.changeSrpHelper = exports.accountCanLoginAdmin = exports.accountCanLogin = exports.accountHasPassword = exports.getFromAccount = exports.delAccount = exports.addAccount = exports.renameAccount = exports.normalizeUsername = exports.
|
|
7
|
+
exports.changeSrpHelper = exports.accountCanLoginAdmin = exports.accountCanLogin = exports.accountHasPassword = exports.getFromAccount = exports.delAccount = exports.addAccount = exports.renameAccount = exports.normalizeUsername = exports.accounts = exports.updateAccount = exports.createAdmin = exports.saveSrpInfo = exports.getAccount = exports.getUsernames = exports.ctxBelongsTo = exports.expandUsername = void 0;
|
|
8
8
|
const lodash_1 = __importDefault(require("lodash"));
|
|
9
9
|
const misc_1 = require("./misc");
|
|
10
10
|
const config_1 = require("./config");
|
|
@@ -12,7 +12,6 @@ const tssrp6a_1 = require("tssrp6a");
|
|
|
12
12
|
const events_1 = __importDefault(require("./events"));
|
|
13
13
|
const apiMiddleware_1 = require("./apiMiddleware");
|
|
14
14
|
const auth_1 = require("./auth");
|
|
15
|
-
let accounts = {};
|
|
16
15
|
// provides the username and all other usernames it inherits based on the 'belongs' attribute. Useful to check permissions
|
|
17
16
|
function expandUsername(who) {
|
|
18
17
|
const ret = [];
|
|
@@ -36,13 +35,13 @@ function ctxBelongsTo(ctx, usernames) {
|
|
|
36
35
|
}
|
|
37
36
|
exports.ctxBelongsTo = ctxBelongsTo;
|
|
38
37
|
function getUsernames() {
|
|
39
|
-
return Object.keys(accounts);
|
|
38
|
+
return Object.keys(exports.accounts.get());
|
|
40
39
|
}
|
|
41
40
|
exports.getUsernames = getUsernames;
|
|
42
41
|
function getAccount(username, normalize = true) {
|
|
43
42
|
if (normalize)
|
|
44
43
|
username = normalizeUsername(username);
|
|
45
|
-
return username ? accounts[username] : undefined;
|
|
44
|
+
return username ? exports.accounts.get()[username] : undefined;
|
|
46
45
|
}
|
|
47
46
|
exports.getAccount = getAccount;
|
|
48
47
|
function saveSrpInfo(account, salt, verifier) {
|
|
@@ -83,7 +82,7 @@ async function updateAccount(account, change) {
|
|
|
83
82
|
if (account.belongs) {
|
|
84
83
|
account.belongs = (0, misc_1.wantArray)(account.belongs);
|
|
85
84
|
lodash_1.default.remove(account.belongs, b => {
|
|
86
|
-
if (accounts.hasOwnProperty(b))
|
|
85
|
+
if (exports.accounts.get().hasOwnProperty(b))
|
|
87
86
|
return;
|
|
88
87
|
console.error(`account ${username} belongs to non-existing ${b}`);
|
|
89
88
|
return true;
|
|
@@ -99,10 +98,10 @@ async function updateAccount(account, change) {
|
|
|
99
98
|
}
|
|
100
99
|
exports.updateAccount = updateAccount;
|
|
101
100
|
const saveAccountsAsap = config_1.saveConfigAsap;
|
|
102
|
-
exports.
|
|
103
|
-
exports.
|
|
104
|
-
// consider some validation here
|
|
105
|
-
lodash_1.default.each(
|
|
101
|
+
exports.accounts = (0, config_1.defineConfig)('accounts', {});
|
|
102
|
+
exports.accounts.sub(lodash_1.default.debounce(obj => {
|
|
103
|
+
// consider some validation here, in case of manual edit of the config
|
|
104
|
+
lodash_1.default.each(obj, (rec, k) => {
|
|
106
105
|
const norm = normalizeUsername(k);
|
|
107
106
|
if ((rec === null || rec === void 0 ? void 0 : rec.username) !== norm) {
|
|
108
107
|
if (!rec) // an empty object in yaml is parsed as null
|
|
@@ -113,32 +112,32 @@ exports.accountsConfig.sub(obj => {
|
|
|
113
112
|
}
|
|
114
113
|
void updateAccount(rec, {}); // work fields
|
|
115
114
|
});
|
|
116
|
-
});
|
|
115
|
+
})); // don't trigger in the middle of a series of deletion, as we may have an inconsistent state
|
|
117
116
|
function normalizeUsername(username) {
|
|
118
117
|
return username.toLocaleLowerCase();
|
|
119
118
|
}
|
|
120
119
|
exports.normalizeUsername = normalizeUsername;
|
|
121
120
|
function renameAccount(from, to) {
|
|
121
|
+
var _a;
|
|
122
122
|
from = normalizeUsername(from);
|
|
123
|
+
const as = exports.accounts.get();
|
|
123
124
|
to = normalizeUsername(to);
|
|
124
|
-
if (!to || !
|
|
125
|
+
if (!to || !as[from] || as[to])
|
|
125
126
|
return false;
|
|
126
127
|
if (to === from)
|
|
127
128
|
return true;
|
|
128
|
-
(0, misc_1.objRenameKey)(
|
|
129
|
-
|
|
129
|
+
(0, misc_1.objRenameKey)(as, from, to);
|
|
130
|
+
(0, misc_1.setHidden)(as[to], { username: to });
|
|
131
|
+
// update references
|
|
132
|
+
for (const a of Object.values(as)) {
|
|
133
|
+
const idx = (_a = a.belongs) === null || _a === void 0 ? void 0 : _a.indexOf(from);
|
|
134
|
+
if (idx !== undefined && idx >= 0)
|
|
135
|
+
a.belongs[idx] = to;
|
|
136
|
+
}
|
|
137
|
+
exports.accounts.set(as);
|
|
138
|
+
events_1.default.emit('accountRenamed', from, to); // everybody, take care of your stuff
|
|
130
139
|
saveAccountsAsap();
|
|
131
140
|
return true;
|
|
132
|
-
function updateReferences() {
|
|
133
|
-
var _a;
|
|
134
|
-
(0, misc_1.setHidden)(accounts[to], { username: to });
|
|
135
|
-
for (const a of Object.values(accounts)) {
|
|
136
|
-
const idx = (_a = a.belongs) === null || _a === void 0 ? void 0 : _a.indexOf(from);
|
|
137
|
-
if (idx !== undefined && idx >= 0)
|
|
138
|
-
a.belongs[idx] = to;
|
|
139
|
-
}
|
|
140
|
-
events_1.default.emit('accountRenamed', from, to); // everybody, take care of your stuff
|
|
141
|
-
}
|
|
142
141
|
}
|
|
143
142
|
exports.renameAccount = renameAccount;
|
|
144
143
|
function addAccount(username, props, updateExisting = false) {
|
|
@@ -150,14 +149,14 @@ function addAccount(username, props, updateExisting = false) {
|
|
|
150
149
|
return;
|
|
151
150
|
account = (0, misc_1.setHidden)(account || {}, { username }); // hidden so that stringification won't include it
|
|
152
151
|
Object.assign(account, lodash_1.default.pickBy(props, Boolean));
|
|
153
|
-
exports.
|
|
152
|
+
exports.accounts.set(accounts => Object.assign(accounts, { [username]: account }));
|
|
154
153
|
return updateAccount(account, account).then(() => account);
|
|
155
154
|
}
|
|
156
155
|
exports.addAccount = addAccount;
|
|
157
156
|
function delAccount(username) {
|
|
158
157
|
if (!getAccount(username))
|
|
159
158
|
return false;
|
|
160
|
-
exports.
|
|
159
|
+
exports.accounts.set(x => lodash_1.default.omit(x, normalizeUsername(username)));
|
|
161
160
|
saveAccountsAsap();
|
|
162
161
|
return true;
|
|
163
162
|
}
|
package/src/plugins.js
CHANGED
|
@@ -209,7 +209,7 @@ const pluginsMiddleware = async (ctx, next) => {
|
|
|
209
209
|
warnOnce(`plugin ${id} is using deprecated API (return true on middleware) and may not work with future versions (check for an update to "${id}")`);
|
|
210
210
|
}
|
|
211
211
|
// don't just check ctx.isStopped, as the async plugin that called ctx.stop will reach here after sync ones
|
|
212
|
-
if (
|
|
212
|
+
if (ctx.isStopped && !ctx.pluginBlockedRequest)
|
|
213
213
|
console.debug("plugin blocked request", ctx.pluginBlockedRequest = id);
|
|
214
214
|
if (typeof res === 'function')
|
|
215
215
|
after[id] = res;
|
|
@@ -219,7 +219,7 @@ const pluginsMiddleware = async (ctx, next) => {
|
|
|
219
219
|
}
|
|
220
220
|
}));
|
|
221
221
|
// expose public plugins' files`
|
|
222
|
-
if (!ctx.
|
|
222
|
+
if (!ctx.isStopped) {
|
|
223
223
|
const { path } = ctx;
|
|
224
224
|
if (path.startsWith(const_1.PLUGINS_PUB_URI)) {
|
|
225
225
|
const a = path.substring(const_1.PLUGINS_PUB_URI.length).split('/');
|
package/src/roots.js
CHANGED
|
@@ -12,7 +12,7 @@ const lodash_1 = __importDefault(require("lodash"));
|
|
|
12
12
|
exports.roots = (0, config_1.defineConfig)(misc_1.CFG.roots, {}, map => {
|
|
13
13
|
const list = Object.keys(map);
|
|
14
14
|
const matchers = list.map(hostMask => (0, misc_1.makeMatcher)(hostMask));
|
|
15
|
-
const values = Object.values(map);
|
|
15
|
+
const values = Object.values(map).map(x => (0, misc_1.enforceFinal)('/', (0, misc_1.enforceStarting)('/', x)));
|
|
16
16
|
return (host) => values[matchers.findIndex(m => m(host))];
|
|
17
17
|
});
|
|
18
18
|
const forceAddress = (0, config_1.defineConfig)(misc_1.CFG.force_address, false);
|
|
@@ -35,7 +35,7 @@ const rootsMiddleware = (ctx, next) => (() => {
|
|
|
35
35
|
}
|
|
36
36
|
if (lodash_1.default.isEmpty(exports.roots.get()))
|
|
37
37
|
return;
|
|
38
|
-
const root = (_a = exports.roots.compiled()) === null || _a === void 0 ? void 0 : _a(ctx.host);
|
|
38
|
+
const root = ctx.state.root = (_a = exports.roots.compiled()) === null || _a === void 0 ? void 0 : _a(ctx.host);
|
|
39
39
|
if (!ctx.state.skipFilters && forceAddress.get())
|
|
40
40
|
if (root === undefined && !(0, misc_1.isLocalHost)(ctx) && ctx.host !== listen_1.baseUrl.compiled()) {
|
|
41
41
|
(0, connections_1.disconnect)(ctx, forceAddress.key());
|
package/src/serveFile.js
CHANGED
|
@@ -121,9 +121,10 @@ exports.monitorAsDownload = monitorAsDownload;
|
|
|
121
121
|
function applyRange(ctx, totalSize = ctx.response.length) {
|
|
122
122
|
ctx.set('Accept-Ranges', 'bytes');
|
|
123
123
|
const { range } = ctx.request.header;
|
|
124
|
-
if (!range) {
|
|
124
|
+
if (!range || isNaN(totalSize)) {
|
|
125
125
|
ctx.state.includesLastByte = true;
|
|
126
|
-
|
|
126
|
+
if (!isNaN(totalSize))
|
|
127
|
+
ctx.response.length = totalSize;
|
|
127
128
|
return;
|
|
128
129
|
}
|
|
129
130
|
const [unit, ranges] = range.split('=');
|
|
@@ -60,7 +60,7 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
|
|
|
60
60
|
if (ctx.method === 'PUT') { // curl -T file url/
|
|
61
61
|
const decPath = decodeURIComponent(path);
|
|
62
62
|
let rest = (0, path_1.basename)(decPath);
|
|
63
|
-
const folderUri = (0, path_1.dirname)(
|
|
63
|
+
const folderUri = (0, misc_1.pathEncode)((0, path_1.dirname)(decPath)); // re-encode to get readable urls
|
|
64
64
|
const folder = await (0, vfs_1.urlToNode)(folderUri, ctx, vfs_1.vfs, v => rest = v + '/' + rest);
|
|
65
65
|
if (!folder)
|
|
66
66
|
return (0, errorPages_1.sendErrorPage)(ctx, cross_const_1.HTTP_NOT_FOUND);
|
|
@@ -77,7 +77,7 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
|
|
|
77
77
|
}
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
|
-
if (/^\/favicon.ico(\??.*)/.test(ctx.originalUrl) && adminApis_1.favicon.get()) // originalUrl to not be subject to changes (vhosting plugin)
|
|
80
|
+
if (/^\/favicon.ico(\??.*)/.test(ctx.originalUrl) && adminApis_1.favicon.get() && ctx.method === 'GET') // originalUrl to not be subject to changes (vhosting plugin)
|
|
81
81
|
return (0, serveFile_1.serveFile)(ctx, adminApis_1.favicon.get());
|
|
82
82
|
let node = await (0, vfs_1.urlToNode)(path, ctx);
|
|
83
83
|
if (!node)
|
package/src/serveGuiFiles.js
CHANGED
|
@@ -74,9 +74,9 @@ async function treatIndex(ctx, filesUri, body) {
|
|
|
74
74
|
const plugins = Object.fromEntries((0, misc_1.onlyTruthy)((0, plugins_1.mapPlugins)((pl, name) => {
|
|
75
75
|
var _a, _b;
|
|
76
76
|
let configs = (0, misc_1.newObj)((0, plugins_1.getPluginConfigFields)(name), (v, k, skip) => {
|
|
77
|
-
var _a, _b, _c
|
|
77
|
+
var _a, _b, _c;
|
|
78
78
|
return !v.frontend ? skip() :
|
|
79
|
-
((
|
|
79
|
+
adjustValueByConfig((_b = (_a = plugins_1.pluginsConfig.get()) === null || _a === void 0 ? void 0 : _a[name]) === null || _b === void 0 ? void 0 : _b[k], (_c = pl.getData().config) === null || _c === void 0 ? void 0 : _c[k]);
|
|
80
80
|
});
|
|
81
81
|
configs = ((_b = (_a = (0, plugins_1.getPluginInfo)(name)).onFrontendConfig) === null || _b === void 0 ? void 0 : _b.call(_a, configs)) || configs;
|
|
82
82
|
return !lodash_1.default.isEmpty(configs) && [name, configs];
|
|
@@ -142,6 +142,24 @@ async function treatIndex(ctx, filesUri, body) {
|
|
|
142
142
|
return (0, customHtml_1.getSection)('bottom') + all;
|
|
143
143
|
return all; // unchanged
|
|
144
144
|
});
|
|
145
|
+
function adjustValueByConfig(v, cfg) {
|
|
146
|
+
v !== null && v !== void 0 ? v : (v = cfg.defaultValue);
|
|
147
|
+
const { type } = cfg;
|
|
148
|
+
if (v && type === 'vfs_path') {
|
|
149
|
+
v = (0, misc_1.enforceStarting)('/', v);
|
|
150
|
+
const { root } = ctx.state;
|
|
151
|
+
if (root)
|
|
152
|
+
if (v.startsWith(root))
|
|
153
|
+
v = v.slice(root.length - 1);
|
|
154
|
+
else
|
|
155
|
+
return;
|
|
156
|
+
if (ctx.state.revProxyPath)
|
|
157
|
+
v = ctx.state.revProxyPath + v;
|
|
158
|
+
}
|
|
159
|
+
else if (type === 'array' && Array.isArray(v))
|
|
160
|
+
v = v.map(x => (0, misc_1.objSameKeys)(x, (xv, xk) => adjustValueByConfig(xv, cfg.fields[xk])));
|
|
161
|
+
return v;
|
|
162
|
+
}
|
|
145
163
|
}
|
|
146
164
|
function serializeCss(v) {
|
|
147
165
|
var _a;
|
package/src/util-http.js
CHANGED
|
@@ -45,7 +45,7 @@ function httpStream(url, { body, jar, noRedirect, httpThrow, proxy, ...options }
|
|
|
45
45
|
if (jar)
|
|
46
46
|
options.headers.cookie = lodash_1.default.map(jar, (v, k) => `${k}=${v}; `).join('')
|
|
47
47
|
+ (options.headers.cookie || ''); // preserve parameter
|
|
48
|
-
Object.assign(options, lodash_1.default.pick((0, node_url_1.parse)(proxy || url), ['hostname', 'port', 'path', 'protocol']));
|
|
48
|
+
Object.assign(options, lodash_1.default.pick((0, node_url_1.parse)(proxy || url), ['hostname', 'port', 'path', 'protocol', 'auth']));
|
|
49
49
|
if (proxy) {
|
|
50
50
|
options.path = url;
|
|
51
51
|
(_d = (_g = options.headers).host) !== null && _d !== void 0 ? _d : (_g.host = (0, node_url_1.parse)(url).host || undefined);
|
package/src/vfs.js
CHANGED
|
@@ -250,6 +250,7 @@ async function* walkNode(parent, { ctx, depth = Infinity, prefixPath = '', requi
|
|
|
250
250
|
const stream = new node_stream_1.Readable({
|
|
251
251
|
objectMode: true,
|
|
252
252
|
async read() {
|
|
253
|
+
var _a;
|
|
253
254
|
if (started)
|
|
254
255
|
return; // for simplicity, we care about starting, and never suspend
|
|
255
256
|
started = true;
|
|
@@ -266,11 +267,11 @@ async function* walkNode(parent, { ctx, depth = Infinity, prefixPath = '', requi
|
|
|
266
267
|
const item = { ...child, name };
|
|
267
268
|
if (await cantSee(item))
|
|
268
269
|
continue;
|
|
269
|
-
if (item.source) // real items must be accessible
|
|
270
|
+
if (item.source && !((_a = item.children) === null || _a === void 0 ? void 0 : _a.length)) // real items must be accessible, unless there's more to it
|
|
270
271
|
try {
|
|
271
272
|
await promises_1.default.access(item.source);
|
|
272
273
|
}
|
|
273
|
-
catch (
|
|
274
|
+
catch (_b) {
|
|
274
275
|
continue;
|
|
275
276
|
}
|
|
276
277
|
const isFolder = await nodeIsDirectory(child);
|
package/src/zip.js
CHANGED
|
@@ -82,7 +82,6 @@ async function zipStreamFromFolder(node, ctx) {
|
|
|
82
82
|
const zip = new QuickZipStream_1.QuickZipStream(mappedWalker);
|
|
83
83
|
const time = 1000 * zipSeconds.get();
|
|
84
84
|
const size = await zip.calculateSize(time);
|
|
85
|
-
ctx.response.length = size;
|
|
86
85
|
const range = (0, serveFile_1.applyRange)(ctx, size); // keep var size as ctx.response.length won't preserve a NaN
|
|
87
86
|
if (ctx.status >= 400)
|
|
88
87
|
return;
|