hfs 0.42.2 → 0.43.0
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 +9 -12
- package/admin/assets/index-5cd667a5.js +511 -0
- package/admin/assets/index-8ff39373.css +1 -0
- package/{frontend/assets/sha512-bce9fb1c.js → admin/assets/sha512-55ff2fa3.js} +1 -1
- package/admin/index.html +2 -2
- package/frontend/assets/index-27488fde.js +94 -0
- package/frontend/assets/index-54a5c76f.css +1 -0
- package/{admin/assets/sha512-af87c1bd.js → frontend/assets/sha512-8ebf6e2a.js} +1 -1
- package/frontend/fontello.css +9 -3
- package/frontend/fontello.woff2 +0 -0
- package/frontend/index.html +2 -2
- package/package.json +2 -2
- package/plugins/antibrute/plugin.js +1 -1
- package/plugins/download-counter/plugin.js +10 -3
- package/plugins/download-counter/public/main.js +12 -2
- package/src/adminApis.js +3 -3
- package/src/api.accounts.js +2 -1
- package/src/api.file_list.js +15 -2
- package/src/api.lang.js +8 -11
- package/src/api.vfs.js +11 -5
- package/src/block.js +6 -20
- package/src/config.js +6 -2
- package/src/const.js +2 -2
- package/src/customHtml.js +1 -1
- package/src/frontEndApis.js +1 -26
- package/src/lang.js +77 -0
- package/src/langs/hfs-lang-it.json +100 -0
- package/src/langs/hfs-lang-ko.json +103 -0
- package/src/langs/hfs-lang-ru.json +106 -0
- package/src/langs/hfs-lang-sr.json +108 -0
- package/src/langs/hfs-lang-zh.json +98 -0
- package/src/listen.js +8 -3
- package/src/middlewares.js +10 -0
- package/src/misc.js +13 -9
- package/src/perm.js +1 -1
- package/src/serveFile.js +2 -2
- package/src/serveGuiFiles.js +21 -8
- package/src/upload.js +1 -1
- package/src/vfs.js +27 -33
- package/admin/assets/index-1db4299e.js +0 -511
- package/admin/assets/index-94bbe0be.css +0 -1
- package/frontend/assets/index-297a3f3d.js +0 -94
- package/frontend/assets/index-a09cacfd.css +0 -1
package/src/serveFile.js
CHANGED
|
@@ -33,6 +33,8 @@ function serveFileNode(ctx, node) {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
ctx.vfsNode = node; // useful to tell service files from files shared by the user
|
|
36
|
+
if ('dl' in ctx.params) // please, download
|
|
37
|
+
ctx.attachment(name);
|
|
36
38
|
return serveFile(ctx, source || '', mimeString);
|
|
37
39
|
}
|
|
38
40
|
exports.serveFileNode = serveFileNode;
|
|
@@ -41,8 +43,6 @@ async function serveFile(ctx, source, mime, content) {
|
|
|
41
43
|
if (!source)
|
|
42
44
|
return;
|
|
43
45
|
const fn = path_1.default.basename(source);
|
|
44
|
-
if ('dl' in ctx.params) // please, download
|
|
45
|
-
ctx.attachment(fn);
|
|
46
46
|
mime = mime !== null && mime !== void 0 ? mime : lodash_1.default.find(mimeCfg.get(), (v, k) => (0, misc_1.matches)(fn, k));
|
|
47
47
|
if (mime === vfs_1.MIME_AUTO)
|
|
48
48
|
mime = mime_types_1.default.lookup(source) || '';
|
package/src/serveGuiFiles.js
CHANGED
|
@@ -41,6 +41,7 @@ const valtio_1 = require("valtio");
|
|
|
41
41
|
const customHtml_1 = require("./customHtml");
|
|
42
42
|
const lodash_1 = __importDefault(require("lodash"));
|
|
43
43
|
const config_1 = require("./config");
|
|
44
|
+
const lang_1 = require("./lang");
|
|
44
45
|
// in case of dev env we have our static files within the 'dist' folder'
|
|
45
46
|
const DEV_STATIC = process.env.DEV ? 'dist/' : '';
|
|
46
47
|
function serveStatic(uri) {
|
|
@@ -68,8 +69,6 @@ function serveStatic(uri) {
|
|
|
68
69
|
return (0, serveFile_1.serveFile)(ctx, fullPath, 'auto', content);
|
|
69
70
|
// we don't cache the index as it's small and may prevent plugins change to apply
|
|
70
71
|
ctx.body = await treatIndex(ctx, uri, String(content));
|
|
71
|
-
ctx.type = 'html';
|
|
72
|
-
ctx.set('Cache-Control', 'no-store, no-cache, must-revalidate');
|
|
73
72
|
};
|
|
74
73
|
}
|
|
75
74
|
function shouldServeApp(ctx) {
|
|
@@ -84,10 +83,10 @@ function adjustBundlerLinks(ctx, uri, data) {
|
|
|
84
83
|
async function treatIndex(ctx, filesUri, body) {
|
|
85
84
|
const session = await (0, api_auth_1.refresh_session)({}, ctx);
|
|
86
85
|
ctx.set('etag', '');
|
|
86
|
+
ctx.set('Cache-Control', 'no-store, no-cache, must-revalidate');
|
|
87
|
+
ctx.type = 'html';
|
|
87
88
|
const isFrontend = filesUri === const_1.FRONTEND_URI;
|
|
88
89
|
const pub = ctx.state.revProxyPath + const_1.PLUGINS_PUB_URI;
|
|
89
|
-
const css = (0, plugins_1.mapPlugins)((plug, k) => { var _a; return (_a = (isFrontend ? plug.frontend_css : null)) === null || _a === void 0 ? void 0 : _a.map(f => pub + k + '/' + f); }).flat().filter(Boolean);
|
|
90
|
-
const js = (0, plugins_1.mapPlugins)((plug, k) => { var _a; return (_a = (isFrontend ? plug.frontend_js : null)) === null || _a === void 0 ? void 0 : _a.map(f => pub + k + '/' + f); }).flat().filter(Boolean);
|
|
91
90
|
// expose plugins' configs that are declared with 'frontend' attribute
|
|
92
91
|
const plugins = Object.fromEntries((0, misc_1.onlyTruthy)((0, plugins_1.mapPlugins)((pl, name) => {
|
|
93
92
|
var _a, _b;
|
|
@@ -99,6 +98,7 @@ async function treatIndex(ctx, filesUri, body) {
|
|
|
99
98
|
configs = ((_b = (_a = (0, plugins_1.getPluginInfo)(name)).onFrontendConfig) === null || _b === void 0 ? void 0 : _b.call(_a, configs)) || configs;
|
|
100
99
|
return !lodash_1.default.isEmpty(configs) && [name, configs];
|
|
101
100
|
})));
|
|
101
|
+
const lang = await (0, lang_1.getLangData)(ctx);
|
|
102
102
|
let ret = body
|
|
103
103
|
.replace(/((?:src|href) *= *['"])\/?(?![a-z]+:\/\/)/g, '$1' + ctx.state.revProxyPath + filesUri)
|
|
104
104
|
.replace('</head>', () => `
|
|
@@ -115,17 +115,30 @@ async function treatIndex(ctx, filesUri, body) {
|
|
|
115
115
|
plugins,
|
|
116
116
|
prefixUrl: ctx.state.revProxyPath,
|
|
117
117
|
customHtml: lodash_1.default.omit(Object.fromEntries(customHtml_1.customHtmlState.sections), ['top', 'bottom']),
|
|
118
|
-
fileMenuOnLink: fileMenuOnLink.get()
|
|
119
|
-
|
|
118
|
+
fileMenuOnLink: fileMenuOnLink.get(),
|
|
119
|
+
lang
|
|
120
|
+
}, null, 4)
|
|
121
|
+
.replace(/<(\/script)/g, '<"+"$1') /*avoid breaking our script container*/}
|
|
120
122
|
document.documentElement.setAttribute('ver', '${const_1.VERSION.split('-')[0] /*for style selectors*/}')
|
|
123
|
+
HFS.getPluginKey = () => document.currentScript?.getAttribute('plugin')
|
|
124
|
+
|| console.error("this function must be called at the very top of your file")
|
|
125
|
+
HFS.getPluginConfig = () => HFS.plugins[HFS.getPluginKey()]
|
|
121
126
|
</script>
|
|
122
127
|
<style>
|
|
123
128
|
:root {
|
|
124
129
|
${lodash_1.default.map(plugins, (configs, pluginName) => lodash_1.default.map(configs, (v, k) => `--${pluginName}-${k}: ${serializeCss(v)};`).join('\n')).join('')}
|
|
125
130
|
}
|
|
126
131
|
</style>
|
|
127
|
-
${
|
|
128
|
-
|
|
132
|
+
${!isFrontend ? '' : (0, plugins_1.mapPlugins)((plug, k) => {
|
|
133
|
+
var _a;
|
|
134
|
+
return (_a = plug.frontend_css) === null || _a === void 0 ? void 0 : _a.map(f => `<link rel='stylesheet' type='text/css' href='${pub + k + '/' + f}' plugin=${JSON.stringify(k)}/>`);
|
|
135
|
+
})
|
|
136
|
+
.flat().filter(Boolean).join('\n')}
|
|
137
|
+
${!isFrontend ? '' : (0, plugins_1.mapPlugins)((plug, k) => {
|
|
138
|
+
var _a;
|
|
139
|
+
return (_a = plug.frontend_js) === null || _a === void 0 ? void 0 : _a.map(f => `<script defer plugin=${JSON.stringify(k)} src='${pub + k + '/' + f}'></script>`);
|
|
140
|
+
})
|
|
141
|
+
.flat().filter(Boolean).join('\n')}
|
|
129
142
|
</head>`);
|
|
130
143
|
if (isFrontend)
|
|
131
144
|
ret = ret
|
package/src/upload.js
CHANGED
|
@@ -15,7 +15,7 @@ const util_os_1 = require("./util-os");
|
|
|
15
15
|
const connections_1 = require("./connections");
|
|
16
16
|
const throttler_1 = require("./throttler");
|
|
17
17
|
const lodash_1 = __importDefault(require("lodash"));
|
|
18
|
-
exports.deleteUnfinishedUploadsAfter = (0, config_1.defineConfig)('delete_unfinished_uploads_after');
|
|
18
|
+
exports.deleteUnfinishedUploadsAfter = (0, config_1.defineConfig)('delete_unfinished_uploads_after', undefined);
|
|
19
19
|
exports.minAvailableMb = (0, config_1.defineConfig)('min_available_mb', 100);
|
|
20
20
|
const dontOverwriteUploading = (0, config_1.defineConfig)('dont_overwrite_uploading', false);
|
|
21
21
|
const waitingToBeDeleted = {};
|
package/src/vfs.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.walkNode = exports.statusCodeForMissingPerm = exports.hasPermission = exports.nodeIsDirectory = exports.getNodeName = exports.saveVfs = exports.vfs = exports.urlToNode = exports.isSameFilenameAs = exports.MIME_AUTO = exports.defaultPerms = void 0;
|
|
7
|
+
exports.masksCouldGivePermission = exports.walkNode = exports.statusCodeForMissingPerm = exports.hasPermission = exports.nodeIsDirectory = exports.getNodeName = exports.saveVfs = exports.vfs = exports.urlToNode = exports.isSameFilenameAs = exports.MIME_AUTO = exports.defaultPerms = exports.WHO_ANY_ACCOUNT = exports.WHO_NO_ONE = exports.WHO_ANYONE = void 0;
|
|
8
8
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
9
|
const path_1 = require("path");
|
|
10
10
|
const misc_1 = require("./misc");
|
|
@@ -13,15 +13,15 @@ const config_1 = require("./config");
|
|
|
13
13
|
const const_1 = require("./const");
|
|
14
14
|
const events_1 = __importDefault(require("./events"));
|
|
15
15
|
const perm_1 = require("./perm");
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
exports.WHO_ANYONE = true;
|
|
17
|
+
exports.WHO_NO_ONE = false;
|
|
18
|
+
exports.WHO_ANY_ACCOUNT = '*';
|
|
19
19
|
exports.defaultPerms = {
|
|
20
|
-
can_see: WHO_ANYONE,
|
|
21
|
-
can_read: WHO_ANYONE,
|
|
22
|
-
can_list: WHO_ANYONE,
|
|
23
|
-
can_upload: WHO_NO_ONE,
|
|
24
|
-
can_delete: WHO_NO_ONE,
|
|
20
|
+
can_see: exports.WHO_ANYONE,
|
|
21
|
+
can_read: exports.WHO_ANYONE,
|
|
22
|
+
can_list: exports.WHO_ANYONE,
|
|
23
|
+
can_upload: exports.WHO_NO_ONE,
|
|
24
|
+
can_delete: exports.WHO_NO_ONE,
|
|
25
25
|
};
|
|
26
26
|
exports.MIME_AUTO = 'auto';
|
|
27
27
|
function inheritFromParent(parent, child) {
|
|
@@ -104,16 +104,18 @@ function saveVfs() {
|
|
|
104
104
|
}
|
|
105
105
|
exports.saveVfs = saveVfs;
|
|
106
106
|
function getNodeName(node) {
|
|
107
|
-
const { name, source
|
|
107
|
+
const { name, source } = node;
|
|
108
108
|
if (name)
|
|
109
109
|
return name;
|
|
110
|
-
if (!
|
|
110
|
+
if (!source)
|
|
111
111
|
return ''; // should happen only for root
|
|
112
|
-
if (
|
|
113
|
-
return
|
|
114
|
-
|
|
112
|
+
if (source === '/')
|
|
113
|
+
return 'root';
|
|
114
|
+
if (/^[a-zA-Z]:\\?$/.test(source))
|
|
115
|
+
return source.slice(0, 2); // exclude trailing slash
|
|
116
|
+
const base = (0, path_1.basename)(source);
|
|
115
117
|
if (/^[./\\]*$/.test(base)) // if empty or special-chars-only
|
|
116
|
-
return (0, path_1.basename)((0, path_1.resolve)(
|
|
118
|
+
return (0, path_1.basename)((0, path_1.resolve)(source)); // resolve to try to get more
|
|
117
119
|
return base;
|
|
118
120
|
}
|
|
119
121
|
exports.getNodeName = getNodeName;
|
|
@@ -137,10 +139,6 @@ exports.statusCodeForMissingPerm = statusCodeForMissingPerm;
|
|
|
137
139
|
// Too many parameters: consider object, but benchmark against degraded recursion on huge folders.
|
|
138
140
|
async function* walkNode(parent, ctx, depth = 0, prefixPath = '', requiredPerm) {
|
|
139
141
|
var _a;
|
|
140
|
-
if (requiredPerm && ctx
|
|
141
|
-
&& !hasPermission(parent, requiredPerm, ctx)
|
|
142
|
-
&& !masksCouldGivePermission(parent.masks))
|
|
143
|
-
return; // no permission, no reason to continue
|
|
144
142
|
const { children, source } = parent;
|
|
145
143
|
const took = prefixPath ? undefined : new Set();
|
|
146
144
|
if (children)
|
|
@@ -160,6 +158,10 @@ async function* walkNode(parent, ctx, depth = 0, prefixPath = '', requiredPerm)
|
|
|
160
158
|
}
|
|
161
159
|
if (!source)
|
|
162
160
|
return;
|
|
161
|
+
if (requiredPerm && ctx // no permission, no reason to continue (at least for dynamic elements)
|
|
162
|
+
&& !hasPermission(parent, requiredPerm, ctx)
|
|
163
|
+
&& !masksCouldGivePermission(parent.masks, requiredPerm))
|
|
164
|
+
return;
|
|
163
165
|
try {
|
|
164
166
|
let lastDir = prefixPath.slice(0, -1) || '.';
|
|
165
167
|
const map = new Map();
|
|
@@ -201,20 +203,12 @@ async function* walkNode(parent, ctx, depth = 0, prefixPath = '', requiredPerm)
|
|
|
201
203
|
item.isTemp = true;
|
|
202
204
|
return item;
|
|
203
205
|
}
|
|
204
|
-
function masksCouldGivePermission(masks) {
|
|
205
|
-
if (!masks)
|
|
206
|
-
return false;
|
|
207
|
-
for (const [, props] of Object.entries(masks)) {
|
|
208
|
-
const v = props[requiredPerm];
|
|
209
|
-
if (v && (!ctx || matchWho(v, ctx))) // without ctx we can't say, so it could
|
|
210
|
-
return true;
|
|
211
|
-
if (masksCouldGivePermission(props.masks))
|
|
212
|
-
return true;
|
|
213
|
-
}
|
|
214
|
-
return false;
|
|
215
|
-
}
|
|
216
206
|
}
|
|
217
207
|
exports.walkNode = walkNode;
|
|
208
|
+
function masksCouldGivePermission(masks, perm) {
|
|
209
|
+
return masks !== undefined && Object.values(masks).some(props => props[perm] || masksCouldGivePermission(props.masks, perm));
|
|
210
|
+
}
|
|
211
|
+
exports.masksCouldGivePermission = masksCouldGivePermission;
|
|
218
212
|
function applyMasks(item, parent, virtualBasename) {
|
|
219
213
|
const { masks } = parent;
|
|
220
214
|
if (!masks)
|
|
@@ -246,8 +240,8 @@ function renameUnderPath(rename, path) {
|
|
|
246
240
|
return lodash_1.default.isEmpty(rename) ? undefined : rename;
|
|
247
241
|
}
|
|
248
242
|
function matchWho(who, ctx) {
|
|
249
|
-
return who === WHO_ANYONE
|
|
250
|
-
|| who === WHO_ANY_ACCOUNT && Boolean(ctx.state.account)
|
|
243
|
+
return who === exports.WHO_ANYONE
|
|
244
|
+
|| who === exports.WHO_ANY_ACCOUNT && Boolean(ctx.state.account)
|
|
251
245
|
|| Array.isArray(who) // check if I or any ancestor match `who`, but cache ancestors' usernames inside context state
|
|
252
246
|
&& (0, misc_1.getOrSet)(ctx.state, 'usernames', () => (0, perm_1.getCurrentUsernameExpanded)(ctx)).some((u) => who.includes(u));
|
|
253
247
|
}
|