hfs 0.45.0 → 0.46.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 +7 -16
- package/admin/assets/index-963c15a5.js +517 -0
- package/{frontend/assets/sha512-b32d8af7.js → admin/assets/sha512-471fbd54.js} +2 -2
- package/admin/index.html +1 -1
- package/frontend/assets/index-c0f02a72.js +94 -0
- package/frontend/assets/index-f2f8fd6b.css +1 -0
- package/{admin/assets/sha512-c0389c0d.js → frontend/assets/sha512-7dcc825b.js} +2 -2
- package/frontend/fontello.css +1 -1
- package/frontend/index.html +2 -3
- package/package.json +4 -3
- package/plugins/download-counter/plugin.js +3 -1
- package/plugins/download-counter/public/main.js +3 -2
- package/plugins/list-uploader/plugin.js +21 -0
- package/plugins/list-uploader/public/main.js +27 -0
- package/plugins/vhosting/plugin.js +6 -3
- package/src/adminApis.js +9 -3
- package/src/api.auth.js +4 -4
- package/src/api.file_list.js +4 -5
- package/src/api.monitor.js +7 -5
- package/src/api.plugins.js +57 -13
- package/src/api.vfs.js +2 -1
- package/src/apiMiddleware.js +4 -0
- package/src/commands.js +11 -0
- package/src/config.js +9 -5
- package/src/connections.js +1 -1
- package/src/const.js +4 -3
- package/src/frontEndApis.js +33 -1
- package/src/github.js +65 -33
- package/src/index.js +4 -4
- package/src/lang.js +3 -2
- package/src/langs/embedded.js +2 -1
- package/src/langs/hfs-lang-fr.json +16 -4
- package/src/langs/hfs-lang-it.json +11 -4
- package/src/langs/hfs-lang-ru.json +16 -4
- package/src/langs/hfs-lang-vi.json +116 -0
- package/src/log.js +50 -47
- package/src/middlewares.js +10 -3
- package/src/plugins.js +181 -98
- package/src/serveFile.js +13 -5
- package/src/serveGuiFiles.js +8 -10
- package/src/throttler.js +11 -6
- package/src/update.js +1 -4
- package/src/upload.js +26 -9
- package/src/util-files.js +25 -6
- package/src/vfs.js +6 -12
- package/src/zip.js +2 -2
- package/admin/assets/index-101f19c9.js +0 -510
- package/frontend/assets/index-59572489.css +0 -1
- package/frontend/assets/index-5aeff3af.js +0 -94
package/src/commands.js
CHANGED
|
@@ -12,6 +12,7 @@ const listen_1 = require("./listen");
|
|
|
12
12
|
const yaml_1 = __importDefault(require("yaml"));
|
|
13
13
|
const const_1 = require("./const");
|
|
14
14
|
const readline_1 = require("readline");
|
|
15
|
+
const plugins_1 = require("./plugins");
|
|
15
16
|
if (!const_1.argv.updating)
|
|
16
17
|
try {
|
|
17
18
|
/*
|
|
@@ -111,6 +112,8 @@ const commands = {
|
|
|
111
112
|
params: '',
|
|
112
113
|
async cb() {
|
|
113
114
|
const update = await (0, update_1.getUpdate)();
|
|
115
|
+
if (update.name === const_1.VERSION)
|
|
116
|
+
throw "you already have the latest version: " + const_1.VERSION;
|
|
114
117
|
console.log("new version available", update.name);
|
|
115
118
|
}
|
|
116
119
|
},
|
|
@@ -121,4 +124,12 @@ const commands = {
|
|
|
121
124
|
console.log(const_1.BUILD_TIMESTAMP);
|
|
122
125
|
}
|
|
123
126
|
},
|
|
127
|
+
'start-plugin': {
|
|
128
|
+
params: '<name>',
|
|
129
|
+
cb: plugins_1.startPlugin,
|
|
130
|
+
},
|
|
131
|
+
'stop-plugin': {
|
|
132
|
+
params: '<name>',
|
|
133
|
+
cb: plugins_1.stopPlugin,
|
|
134
|
+
},
|
|
124
135
|
};
|
package/src/config.js
CHANGED
|
@@ -15,6 +15,7 @@ const fs_1 = require("fs");
|
|
|
15
15
|
const path_1 = require("path");
|
|
16
16
|
const events_2 = __importDefault(require("./events"));
|
|
17
17
|
const os_1 = require("os");
|
|
18
|
+
const promises_1 = require("fs/promises");
|
|
18
19
|
const FILE = 'config.yaml';
|
|
19
20
|
// keep definition of config properties
|
|
20
21
|
const configProps = {};
|
|
@@ -67,7 +68,7 @@ const currentVersion = new Version(const_1.VERSION);
|
|
|
67
68
|
const configVersion = defineConfig('version', const_1.VERSION, v => new Version(v));
|
|
68
69
|
function defineConfig(k, defaultValue, compiler) {
|
|
69
70
|
configProps[k] = { defaultValue };
|
|
70
|
-
let compiled = compiler === null || compiler === void 0 ? void 0 : compiler(defaultValue,
|
|
71
|
+
let compiled = compiler === null || compiler === void 0 ? void 0 : compiler(defaultValue, { version: currentVersion, defaultValue });
|
|
71
72
|
const ret = {
|
|
72
73
|
key() {
|
|
73
74
|
return k;
|
|
@@ -77,7 +78,7 @@ function defineConfig(k, defaultValue, compiler) {
|
|
|
77
78
|
},
|
|
78
79
|
sub(cb) {
|
|
79
80
|
if (started) // initial event already passed, we'll make the first call
|
|
80
|
-
cb(getConfig(k), defaultValue, configVersion.compiled());
|
|
81
|
+
cb(getConfig(k), { was: defaultValue, defaultValue, version: configVersion.compiled() });
|
|
81
82
|
const eventName = CONFIG_CHANGE_EVENT_PREFIX + k;
|
|
82
83
|
return (0, misc_1.onOff)(cfgEvents, {
|
|
83
84
|
[eventName]() {
|
|
@@ -183,9 +184,12 @@ function setConfig1(k, newV, saveChanges = true, valueVersion) {
|
|
|
183
184
|
const saveDebounced = (0, misc_1.debounceAsync)(async () => {
|
|
184
185
|
while (!started)
|
|
185
186
|
await (0, misc_1.wait)(100);
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
187
|
+
// keep backup
|
|
188
|
+
const bak = filePath + '.bak';
|
|
189
|
+
const aWeekAgo = Date.now() - const_1.DAY * 7;
|
|
190
|
+
if (await (0, promises_1.stat)(bak).then(x => aWeekAgo > Number(x.mtime || x.ctime), () => true))
|
|
191
|
+
await (0, promises_1.copyFile)(filePath, bak).catch(() => { }); // ignore errors
|
|
192
|
+
const txt = yaml_1.default.stringify({ ...state, version: const_1.VERSION }, { lineWidth: 1000 });
|
|
189
193
|
save(filePath, txt)
|
|
190
194
|
.catch(err => console.error('Failed at saving config file, please ensure it is writable.', String(err)));
|
|
191
195
|
});
|
package/src/connections.js
CHANGED
package/src/const.js
CHANGED
|
@@ -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_BINARY = exports.IS_WINDOWS = exports.HTTP_SERVER_ERROR = exports.HTTP_FOOL = exports.HTTP_RANGE_NOT_SATISFIABLE = exports.HTTP_PAYLOAD_TOO_LARGE = 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.HFS_REPO = exports.COMPATIBLE_API_VERSION = exports.API_VERSION = exports.DAY = exports.VERSION = exports.BUILD_TIMESTAMP = exports.HFS_STARTED = exports.ORIGINAL_CWD = exports.DEV = exports.argv = void 0;
|
|
30
|
+
exports.APP_PATH = exports.IS_BINARY = exports.IS_WINDOWS = exports.HTTP_SERVER_ERROR = exports.HTTP_FAILED_DEPENDENCY = exports.HTTP_FOOL = exports.HTTP_RANGE_NOT_SATISFIABLE = exports.HTTP_PAYLOAD_TOO_LARGE = 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.HFS_REPO = exports.COMPATIBLE_API_VERSION = exports.API_VERSION = 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");
|
|
@@ -38,11 +38,11 @@ exports.DEV = process.env.DEV || exports.argv.dev ? 'DEV' : '';
|
|
|
38
38
|
exports.ORIGINAL_CWD = process.cwd();
|
|
39
39
|
exports.HFS_STARTED = new Date();
|
|
40
40
|
const PKG_PATH = (0, path_1.join)(__dirname, '..', 'package.json');
|
|
41
|
-
exports.BUILD_TIMESTAMP = "2023-
|
|
41
|
+
exports.BUILD_TIMESTAMP = "2023-07-03T16:52:49.276Z";
|
|
42
42
|
const pkg = JSON.parse(fs.readFileSync(PKG_PATH, 'utf8'));
|
|
43
43
|
exports.VERSION = pkg.version;
|
|
44
44
|
exports.DAY = 86400000;
|
|
45
|
-
exports.API_VERSION = 8.
|
|
45
|
+
exports.API_VERSION = 8.23;
|
|
46
46
|
exports.COMPATIBLE_API_VERSION = 1; // while changes in the api are not breaking, this number stays the same, otherwise it is made equal to API_VERSION
|
|
47
47
|
exports.HFS_REPO = 'rejetto/hfs';
|
|
48
48
|
exports.SPECIAL_URI = '/~/';
|
|
@@ -65,6 +65,7 @@ exports.HTTP_CONFLICT = 409;
|
|
|
65
65
|
exports.HTTP_PAYLOAD_TOO_LARGE = 413;
|
|
66
66
|
exports.HTTP_RANGE_NOT_SATISFIABLE = 416;
|
|
67
67
|
exports.HTTP_FOOL = 418;
|
|
68
|
+
exports.HTTP_FAILED_DEPENDENCY = 424;
|
|
68
69
|
exports.HTTP_SERVER_ERROR = 500;
|
|
69
70
|
exports.IS_WINDOWS = process.platform === 'win32';
|
|
70
71
|
exports.IS_BINARY = !(0, path_1.basename)(process.execPath).includes('node'); // this won't be node if pkg was used
|
package/src/frontEndApis.js
CHANGED
|
@@ -38,6 +38,7 @@ const const_1 = require("./const");
|
|
|
38
38
|
const vfs_1 = require("./vfs");
|
|
39
39
|
const promises_1 = require("fs/promises");
|
|
40
40
|
const path_1 = require("path");
|
|
41
|
+
const upload_1 = require("./upload");
|
|
41
42
|
exports.customHeader = (0, config_1.defineConfig)('custom_header', '');
|
|
42
43
|
exports.frontEndApis = {
|
|
43
44
|
file_list: api_file_list_1.file_list,
|
|
@@ -52,6 +53,15 @@ exports.frontEndApis = {
|
|
|
52
53
|
}
|
|
53
54
|
});
|
|
54
55
|
},
|
|
56
|
+
async get_file_details({ uri }, ctx) {
|
|
57
|
+
apiAssertTypes({ string: { uri } });
|
|
58
|
+
const node = await (0, vfs_1.urlToNode)(uri, ctx);
|
|
59
|
+
if (!node)
|
|
60
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
|
|
61
|
+
return {
|
|
62
|
+
upload: node.source && await (0, upload_1.getUploadMeta)(node.source).catch(() => undefined)
|
|
63
|
+
};
|
|
64
|
+
},
|
|
55
65
|
async create_folder({ uri, name }, ctx) {
|
|
56
66
|
apiAssertTypes({ string: { uri, name } });
|
|
57
67
|
if (!(0, util_files_1.isValidFileName)(name) || (0, util_files_1.dirTraversal)(name))
|
|
@@ -69,7 +79,7 @@ exports.frontEndApis = {
|
|
|
69
79
|
return new apiMiddleware_1.ApiError(e.code === 'EEXIST' ? const_1.HTTP_CONFLICT : const_1.HTTP_BAD_REQUEST, e);
|
|
70
80
|
}
|
|
71
81
|
},
|
|
72
|
-
async
|
|
82
|
+
async delete({ uri }, ctx) {
|
|
73
83
|
apiAssertTypes({ string: { uri } });
|
|
74
84
|
const node = await (0, vfs_1.urlToNode)(uri, ctx);
|
|
75
85
|
if (!node)
|
|
@@ -86,6 +96,28 @@ exports.frontEndApis = {
|
|
|
86
96
|
throw new apiMiddleware_1.ApiError(e.code || const_1.HTTP_SERVER_ERROR, e);
|
|
87
97
|
}
|
|
88
98
|
},
|
|
99
|
+
async rename({ uri, dest }, ctx) {
|
|
100
|
+
apiAssertTypes({ string: { uri, dest } });
|
|
101
|
+
if (dest.includes('/') || (0, util_files_1.dirTraversal)(dest))
|
|
102
|
+
throw new apiMiddleware_1.ApiError(const_1.HTTP_FORBIDDEN);
|
|
103
|
+
const node = await (0, vfs_1.urlToNode)(uri, ctx);
|
|
104
|
+
if (!node)
|
|
105
|
+
throw new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
|
|
106
|
+
if (!(0, vfs_1.hasPermission)(node, 'can_delete', ctx))
|
|
107
|
+
throw new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED);
|
|
108
|
+
try {
|
|
109
|
+
if (node.name)
|
|
110
|
+
node.name = dest;
|
|
111
|
+
else if (node.source)
|
|
112
|
+
await (0, promises_1.rename)(node.source, (0, path_1.join)((0, path_1.dirname)(node.source), dest));
|
|
113
|
+
else
|
|
114
|
+
throw new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR);
|
|
115
|
+
return {};
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
throw new apiMiddleware_1.ApiError(e.code || const_1.HTTP_SERVER_ERROR, e);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
89
121
|
};
|
|
90
122
|
function notifyClient(ctx, name, data) {
|
|
91
123
|
const { notificationChannel } = ctx.query;
|
package/src/github.js
CHANGED
|
@@ -11,7 +11,9 @@ const plugins_1 = require("./plugins");
|
|
|
11
11
|
const apiMiddleware_1 = require("./apiMiddleware");
|
|
12
12
|
const lodash_1 = __importDefault(require("lodash"));
|
|
13
13
|
const const_1 = require("./const");
|
|
14
|
-
const
|
|
14
|
+
const promises_1 = require("fs/promises");
|
|
15
|
+
const path_1 = require("path");
|
|
16
|
+
const DIST_ROOT = 'dist';
|
|
15
17
|
const downloading = {};
|
|
16
18
|
function downloadProgress(id, status) {
|
|
17
19
|
if (status === undefined)
|
|
@@ -23,25 +25,47 @@ function downloadProgress(id, status) {
|
|
|
23
25
|
async function downloadPlugin(repo, branch = '', overwrite) {
|
|
24
26
|
if (downloading[repo])
|
|
25
27
|
return new apiMiddleware_1.ApiError(const_1.HTTP_CONFLICT, "already downloading");
|
|
28
|
+
console.log('downloading plugin', repo);
|
|
26
29
|
downloadProgress(repo, true);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
branch
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
: short
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
30
|
+
try {
|
|
31
|
+
const rec = await getRepoInfo(repo);
|
|
32
|
+
if (!branch)
|
|
33
|
+
branch = rec.default_branch;
|
|
34
|
+
const short = repo.split('/')[1]; // second part, repo without the owner
|
|
35
|
+
if (!short)
|
|
36
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST, "bad repo");
|
|
37
|
+
const folder2repo = getFolder2repo();
|
|
38
|
+
const folder = overwrite ? lodash_1.default.findKey(folder2repo, x => x === repo) // use existing folder
|
|
39
|
+
: short in folder2repo ? repo.replace('/', '-') // longer form only if another plugin is using short form
|
|
40
|
+
: short;
|
|
41
|
+
const installPath = plugins_1.PATH + '/' + folder;
|
|
42
|
+
const GITHUB_ZIP_ROOT = short + '-' + branch; // GitHub puts everything within this folder
|
|
43
|
+
const rootWithinZip = GITHUB_ZIP_ROOT + '/' + DIST_ROOT;
|
|
44
|
+
const foldersToCopy = [
|
|
45
|
+
rootWithinZip + '-' + process.platform + '-' + process.arch,
|
|
46
|
+
rootWithinZip + '-' + process.platform,
|
|
47
|
+
rootWithinZip,
|
|
48
|
+
].map(x => x + '/');
|
|
49
|
+
// this zip doesn't have content-length, so we cannot produce progress event
|
|
50
|
+
const stream = await (0, misc_1.httpsStream)(`https://github.com/${repo}/archive/refs/heads/${branch}.zip`);
|
|
51
|
+
const MAIN = 'plugin.js';
|
|
52
|
+
await (0, misc_1.unzip)(stream, async (path) => {
|
|
53
|
+
const folder = foldersToCopy.find(x => path.startsWith(x));
|
|
54
|
+
if (!folder || path.endsWith('/'))
|
|
55
|
+
return false;
|
|
56
|
+
let dest = path.slice(folder.length);
|
|
57
|
+
if (dest === MAIN) // avoid being possibly loaded before the download is complete
|
|
58
|
+
dest += plugins_1.DISABLING_POSTFIX;
|
|
59
|
+
dest = (0, path_1.join)(installPath, dest);
|
|
60
|
+
return (0, promises_1.rm)(dest, { force: true }).then(() => dest, () => false);
|
|
61
|
+
});
|
|
62
|
+
const main = (0, path_1.join)(installPath, MAIN);
|
|
63
|
+
await (0, promises_1.rename)(main + plugins_1.DISABLING_POSTFIX, main); // we are good now, restore name
|
|
64
|
+
return folder;
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
downloadProgress(repo, undefined);
|
|
68
|
+
}
|
|
45
69
|
}
|
|
46
70
|
exports.downloadPlugin = downloadPlugin;
|
|
47
71
|
function getRepoInfo(id) {
|
|
@@ -53,9 +77,10 @@ function readGithubFile(uri) {
|
|
|
53
77
|
.then(res => res.body);
|
|
54
78
|
}
|
|
55
79
|
exports.readGithubFile = readGithubFile;
|
|
56
|
-
async function readOnlinePlugin(
|
|
57
|
-
|
|
58
|
-
const
|
|
80
|
+
async function readOnlinePlugin(repo, branch = '') {
|
|
81
|
+
branch || (branch = (await getRepoInfo(repo)).default_branch);
|
|
82
|
+
const res = await readGithubFile(`${repo}/${branch}/${DIST_ROOT}/plugin.js`);
|
|
83
|
+
const pl = (0, plugins_1.parsePluginSource)(repo, res); // use 'repo' as 'id' client-side
|
|
59
84
|
pl.branch = branch || undefined;
|
|
60
85
|
return pl;
|
|
61
86
|
}
|
|
@@ -67,15 +92,22 @@ function getFolder2repo() {
|
|
|
67
92
|
}
|
|
68
93
|
exports.getFolder2repo = getFolder2repo;
|
|
69
94
|
async function apiGithub(uri) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
95
|
+
try {
|
|
96
|
+
const res = await (0, misc_1.httpsString)('https://api.github.com/' + uri, {
|
|
97
|
+
headers: {
|
|
98
|
+
'User-Agent': 'HFS',
|
|
99
|
+
Accept: 'application/vnd.github.v3+json',
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
if (!res.ok)
|
|
103
|
+
throw res.statusCode;
|
|
104
|
+
return JSON.parse(res.body);
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
// https://docs.github.com/en/rest/overview/resources-in-the-rest-api?apiVersion=2022-11-28#rate-limiting
|
|
108
|
+
throw e.message === '403' ? Error('github_quota')
|
|
109
|
+
: e;
|
|
110
|
+
}
|
|
79
111
|
}
|
|
80
112
|
async function* searchPlugins(text = '') {
|
|
81
113
|
var _a, _b;
|
|
@@ -85,7 +117,7 @@ async function* searchPlugins(text = '') {
|
|
|
85
117
|
const repo = it.full_name;
|
|
86
118
|
if ((_a = projectInfo === null || projectInfo === void 0 ? void 0 : projectInfo.plugins_blacklist) === null || _a === void 0 ? void 0 : _a.includes(repo))
|
|
87
119
|
continue;
|
|
88
|
-
let pl = await readOnlinePlugin(it);
|
|
120
|
+
let pl = await readOnlinePlugin(repo, it.default_branch);
|
|
89
121
|
if (!pl.apiRequired)
|
|
90
122
|
continue; // mandatory field
|
|
91
123
|
if (pl.badApi) { // we try other branches (starting with 'api')
|
|
@@ -106,7 +138,7 @@ async function* searchPlugins(text = '') {
|
|
|
106
138
|
Object.assign(pl, {
|
|
107
139
|
downloading: downloading[repo],
|
|
108
140
|
license: (_b = it.license) === null || _b === void 0 ? void 0 : _b.spdx_id,
|
|
109
|
-
}, lodash_1.default.pick(it, ['pushed_at', 'stargazers_count']));
|
|
141
|
+
}, lodash_1.default.pick(it, ['pushed_at', 'stargazers_count', 'default_branch']));
|
|
110
142
|
yield pl;
|
|
111
143
|
}
|
|
112
144
|
}
|
package/src/index.js
CHANGED
|
@@ -30,12 +30,12 @@ exports.app = new koa_1.default({ keys });
|
|
|
30
30
|
exports.app.use(middlewares_1.someSecurity)
|
|
31
31
|
.use((0, koa_session_1.default)({ key: 'hfs_$id', signed: true, rolling: true }, exports.app))
|
|
32
32
|
.use(middlewares_1.prepareState)
|
|
33
|
-
.use(middlewares_1.headRequests)
|
|
34
|
-
.use((0, log_1.log)())
|
|
35
|
-
.use(throttler_1.throttler)
|
|
36
33
|
.use(middlewares_1.gzipper)
|
|
37
34
|
.use(middlewares_1.paramsDecoder) // must be done before plugins, so they can manipulate params
|
|
38
|
-
.use(
|
|
35
|
+
.use(plugins_1.pluginsMiddleware)
|
|
36
|
+
.use(middlewares_1.headRequests)
|
|
37
|
+
.use(log_1.logMw)
|
|
38
|
+
.use(throttler_1.throttler)
|
|
39
39
|
.use((0, koa_mount_1.default)(const_1.API_URI, (0, apiMiddleware_1.apiMiddleware)({ ...frontEndApis_1.frontEndApis, ...adminApis_1.adminApis })))
|
|
40
40
|
.use(middlewares_1.serveGuiAndSharedFiles)
|
|
41
41
|
.on('error', errorHandler);
|
package/src/lang.js
CHANGED
|
@@ -59,11 +59,12 @@ let undo;
|
|
|
59
59
|
undo === null || undo === void 0 ? void 0 : undo();
|
|
60
60
|
if (!v)
|
|
61
61
|
return forceLangData = undefined;
|
|
62
|
-
|
|
62
|
+
const translation = embedded_1.default[v];
|
|
63
|
+
forceLangData = { [v]: translation };
|
|
63
64
|
if (v === EMBEDDED_LANGUAGE)
|
|
64
65
|
return;
|
|
65
66
|
const res = (0, watchLoad_1.watchLoad)(code2file(v), data => {
|
|
66
|
-
forceLangData = { [v]:
|
|
67
|
+
forceLangData = { [v]: (0, misc_1.tryJson)(data) || translation };
|
|
67
68
|
});
|
|
68
69
|
undo = res.unwatch;
|
|
69
70
|
});
|
package/src/langs/embedded.js
CHANGED
|
@@ -12,4 +12,5 @@ const hfs_lang_ms_json_1 = __importDefault(require("./hfs-lang-ms.json"));
|
|
|
12
12
|
const hfs_lang_zh_tw_json_1 = __importDefault(require("./hfs-lang-zh-tw.json"));
|
|
13
13
|
const hfs_lang_fr_json_1 = __importDefault(require("./hfs-lang-fr.json"));
|
|
14
14
|
const hfs_lang_pt_json_1 = __importDefault(require("./hfs-lang-pt.json"));
|
|
15
|
-
|
|
15
|
+
const hfs_lang_vi_json_1 = __importDefault(require("./hfs-lang-vi.json"));
|
|
16
|
+
exports.default = { it: hfs_lang_it_json_1.default, zh: hfs_lang_zh_json_1.default, ru: hfs_lang_ru_json_1.default, sr: hfs_lang_sr_json_1.default, ko: hfs_lang_ko_json_1.default, ms: hfs_lang_ms_json_1.default, 'zh-tw': hfs_lang_zh_tw_json_1.default, fr: hfs_lang_fr_json_1.default, pt: hfs_lang_pt_json_1.default, vi: hfs_lang_vi_json_1.default };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Club Microtel Vernon",
|
|
3
|
-
"version": 1.
|
|
4
|
-
"hfs_version": "0.
|
|
3
|
+
"version": 1.2,
|
|
4
|
+
"hfs_version": "0.46.0 Beta",
|
|
5
5
|
"translate": {
|
|
6
6
|
"Select": "Selectionner",
|
|
7
7
|
"n_files": "{n,plural, one{# fichier} other{# fichiers}}",
|
|
@@ -95,12 +95,24 @@
|
|
|
95
95
|
"upload_finished": "{n} terminé(s) ({size})",
|
|
96
96
|
"upload_errors": "{n} échoués",
|
|
97
97
|
"upload_file_rejected": "Certains fichiers ont été refusés",
|
|
98
|
-
"
|
|
98
|
+
"Download counter": "Compteur de téléchargements",
|
|
99
99
|
"File menu": "Menu du fichier",
|
|
100
100
|
"Folder menu": "Menu du dossier",
|
|
101
101
|
"Name": "Nom",
|
|
102
102
|
"file_open": "Ouvrir",
|
|
103
103
|
"Download": "Télécharger",
|
|
104
|
-
"Missing permission": "Permission manquante"
|
|
104
|
+
"Missing permission": "Permission manquante",
|
|
105
|
+
"Reload": "Recharger",
|
|
106
|
+
"Get list": "Lister le contenu",
|
|
107
|
+
"Skip existing files": "Ignorer les fichiers éxistants",
|
|
108
|
+
"Size": "Taille",
|
|
109
|
+
"Timestamp": "Horodatage",
|
|
110
|
+
"Show": "Afficher",
|
|
111
|
+
"Loading failed": "Le chargement a échoué",
|
|
112
|
+
"Rename": "Renommer",
|
|
113
|
+
"Tiles mode:": "Mode tuiles:",
|
|
114
|
+
"off": "Désactivé",
|
|
115
|
+
"Operation successful": "Opération réussie",
|
|
116
|
+
"Uploader": "Téléchargeur"
|
|
105
117
|
}
|
|
106
118
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Massimo Melina",
|
|
3
|
-
"version": 1.
|
|
4
|
-
"hfs_version": "0.
|
|
3
|
+
"version": 1.6,
|
|
4
|
+
"hfs_version": "0.46.0",
|
|
5
5
|
"translate": {
|
|
6
6
|
"Select": "Seleziona",
|
|
7
7
|
"n_files": "{n} file",
|
|
@@ -89,7 +89,6 @@
|
|
|
89
89
|
"upload_finished": "{n,plural, one{# riuscito} other{# riusciti}} ({size})",
|
|
90
90
|
"upload_errors": "{n,plural, one{# fallito} other{# falliti}}",
|
|
91
91
|
"upload_file_rejected": "Alcuni file non sono stati accettati",
|
|
92
|
-
"download counter": "download conteggiati",
|
|
93
92
|
"File menu": "Menu file",
|
|
94
93
|
"Folder menu": "Menu cartella",
|
|
95
94
|
"Name": "Nome",
|
|
@@ -100,6 +99,14 @@
|
|
|
100
99
|
"Get list": "Lista",
|
|
101
100
|
"Skip existing files": "Salta file esistenti",
|
|
102
101
|
"Size": "Dimensione",
|
|
103
|
-
"Timestamp": "Data/ora"
|
|
102
|
+
"Timestamp": "Data/ora",
|
|
103
|
+
"Show": "Show",
|
|
104
|
+
"Loading failed": "Caricamento fallito",
|
|
105
|
+
"Rename": "Rinomina",
|
|
106
|
+
"Tiles mode:": "Griglia:",
|
|
107
|
+
"off": "no",
|
|
108
|
+
"Operation successful": "Operazione riuscita",
|
|
109
|
+
"Uploader": "Upload da",
|
|
110
|
+
"Download counter": "Download conteggiati"
|
|
104
111
|
}
|
|
105
112
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Mefistofell, SanokKule",
|
|
3
|
-
"version": 1.
|
|
4
|
-
"hfs_version": "0.
|
|
3
|
+
"version": 1.97,
|
|
4
|
+
"hfs_version": "0.46.0",
|
|
5
5
|
"translate": {
|
|
6
6
|
"Select": "Выбор",
|
|
7
7
|
"n_files": "{n,plural, one{1 файл} few{# файла} other{# файлов}}",
|
|
@@ -95,12 +95,24 @@
|
|
|
95
95
|
"upload_finished": "{n,plural, one{# файл загружен} few{# файла загружено} other{# файлов загружено}} ({size})",
|
|
96
96
|
"upload_errors": "{n,plural, one{# файл} few{# файла} other{# файлов}} не удалось загрузить",
|
|
97
97
|
"upload_file_rejected": "Некоторые файлы не были приняты",
|
|
98
|
-
"download counter": "Количество скачиваний",
|
|
99
98
|
"File menu": "Меню файла",
|
|
100
99
|
"Folder menu": "Меню папки",
|
|
101
100
|
"Name": "Имя",
|
|
102
101
|
"file_open": "Открыть",
|
|
103
102
|
"Download": "Скачать",
|
|
104
|
-
"Missing permission": "Отсутствует доступ"
|
|
103
|
+
"Missing permission": "Отсутствует доступ",
|
|
104
|
+
"Reload": "Обновить",
|
|
105
|
+
"Get list": "Получить список",
|
|
106
|
+
"Skip existing files": "Пропуск существующих файлов",
|
|
107
|
+
"Size": "Размер",
|
|
108
|
+
"Timestamp": "Дата",
|
|
109
|
+
"Show": "Просмотр",
|
|
110
|
+
"Loading failed": "Не удалось загрузить",
|
|
111
|
+
"Rename": "Переименовать",
|
|
112
|
+
"Tiles mode:": "Плитки:",
|
|
113
|
+
"off": "выключено",
|
|
114
|
+
"Operation successful": "Операция успешна",
|
|
115
|
+
"Uploader": "Загрузчик",
|
|
116
|
+
"Download counter": "Счётчик загрузок"
|
|
105
117
|
}
|
|
106
118
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "thenoopy12 (Nguyễn Văn Ngu)",
|
|
3
|
+
"version": 1.16,
|
|
4
|
+
"hfs_version": "0.46_beta8",
|
|
5
|
+
"translate": {
|
|
6
|
+
"Select": "Chọn",
|
|
7
|
+
"n_files": "{n,plural,one{# tập tin} other{# tập tin}}",
|
|
8
|
+
"n_folders": "{n,plural,one{# thư mục} other{# thư mục}}",
|
|
9
|
+
"filter_count": "{n,plural, one{# đã lọc} other{# đã lọc}}",
|
|
10
|
+
"select_count": "{n,plural, one{# đã chọn} other{# đã chọn}}",
|
|
11
|
+
"filter_placeholder": "Nhập vào đây để lọc danh sách bên dưới",
|
|
12
|
+
"Select some files": "Chọn một số tệp",
|
|
13
|
+
"zip_checkboxes": "Sử dụng hộp kiểm để chọn tệp, sau đó bạn có thể sử dụng lại \"Zip\"",
|
|
14
|
+
"zip_tooltip_selected": "Tải xuống các mục đã chọn dưới dạng tệp zip",
|
|
15
|
+
"zip_tooltip_whole": "Tải xuống toàn bộ danh sách (chưa được lọc) dưới dạng một tệp zip. Nếu bạn chọn một số mục, chỉ những phần tử đó sẽ được tải xuống.",
|
|
16
|
+
"zip_confirm_search": "Tải xuống TẤT CẢ kết quả của tìm kiếm này dưới dạng lưu trữ ZIP?",
|
|
17
|
+
"zip_confirm_folder": "Tải xuống TOÀN BỘ thư mục dưới dạng lưu trữ ZIP?",
|
|
18
|
+
"select_tooltip": "Lựa chọn áp dụng cho \"Zip\" và \"Delete\" (nếu có), nhưng bạn cũng có thể lọc danh sách",
|
|
19
|
+
"delete_hint": "Để xóa, trước tiên hãy nhấp vào \"Chọn\"",
|
|
20
|
+
"delete_confirm": "Xoá {n,plural, one{# cái} other{# cái}}?",
|
|
21
|
+
"delete_completed": "Xóa: {n} thành công",
|
|
22
|
+
"delete_failed": ", {n,plural, one{# thất bại} other{# thất bại}}",
|
|
23
|
+
"delete_select": "Chọn gì đó để xóa",
|
|
24
|
+
"Delete": "Xoá",
|
|
25
|
+
"Options": "Tùy chọn",
|
|
26
|
+
"Search": "Tìm kiếm",
|
|
27
|
+
"Zip": "Zip",
|
|
28
|
+
"search_msg": "Tìm kiếm folder này và các sub-folders",
|
|
29
|
+
"Searching": "Đang tìm",
|
|
30
|
+
"Searched": "Đã tìm xong!",
|
|
31
|
+
"Clear search": "Xoá tìm kiếm",
|
|
32
|
+
"Interrupted": "Tiến trình bị gián đoạn! (nôm na có thể bị huỷ bởi người dùng)",
|
|
33
|
+
"stopped_before": "Đã dừng",
|
|
34
|
+
"empty_list": "Trống",
|
|
35
|
+
"filter_none": "Ko có gì để lọc",
|
|
36
|
+
"Admin-panel": "AdminPanel",
|
|
37
|
+
"Login": "Đăng nhập nàh",
|
|
38
|
+
"Username": "Username",
|
|
39
|
+
"Password": "Pass",
|
|
40
|
+
"login_untrusted": "Đăng nhập bị hủy bỏ: danh tính máy chủ không tin cậy",
|
|
41
|
+
"login_bad_credentials": "Thông tin đăng nhập SAI",
|
|
42
|
+
"login_bad_cookies": "Cookies không hoạt động - đăng nhập không thành công",
|
|
43
|
+
"User panel": "UserPanel",
|
|
44
|
+
"Change password": "Đổi pass",
|
|
45
|
+
"enter_pass": "Nhập pass mới",
|
|
46
|
+
"enter_pass2": "NHẬP LẠI pass mới (giống nha)",
|
|
47
|
+
"pass2_mismatch": "Mật khẩu ghi lại SAI, tiến trình bị hủy bỏ.",
|
|
48
|
+
"password_changed": "Đã đổi pass thành công",
|
|
49
|
+
"Logout": "Đăng xuất nàh",
|
|
50
|
+
"connection error": "Lỗi kết nối",
|
|
51
|
+
"Full timestamp:": "Dấu thời gian đầy đủ:",
|
|
52
|
+
"Search was interrupted": "Tìm kiếm bị gián đoạn!",
|
|
53
|
+
"Stop list": "DỪNG",
|
|
54
|
+
"upload_starting": "Tải lên bây giờ sẽ bắt đầu",
|
|
55
|
+
"wrong_account": "Tài khoản {u} ko có quyền, chọn tk khác đi:)",
|
|
56
|
+
"no_upload_here": "Không có quyền tải lên cho thư mục hiện tại",
|
|
57
|
+
"Create folder": "Tạo thư mục",
|
|
58
|
+
"Pick files": "Chọn files",
|
|
59
|
+
"Pick folder": "Chọn folders",
|
|
60
|
+
"send_files": "Gửi {n,plural,one{# file} other{# file}}, {size}",
|
|
61
|
+
"Clear": "Dẹp",
|
|
62
|
+
"failed_upload": "KO thể up {name}",
|
|
63
|
+
"confirm_resume": "Típ tục up?",
|
|
64
|
+
"file too large": "File NẶNG VÃI LOK",
|
|
65
|
+
"Enter folder name": "Nhập tên folder",
|
|
66
|
+
"Successfully created": "Tạo folder thành công!",
|
|
67
|
+
"enter_folder": "Nhập thư mục",
|
|
68
|
+
"folder_exists": "Thư mục này trùng tên!",
|
|
69
|
+
"Sort by": "Sắp xếp theo",
|
|
70
|
+
"name": "Tên",
|
|
71
|
+
"extension": "phần mở rộng",
|
|
72
|
+
"size": "Kíck cỡ",
|
|
73
|
+
"time": "Thời gian",
|
|
74
|
+
"Invert order": "Đảo ngược thứ tự",
|
|
75
|
+
"Folders first": "Thư mục trước",
|
|
76
|
+
"Numeric names": "Tên số",
|
|
77
|
+
"theme:": "Màu:",
|
|
78
|
+
"auto": "Auto",
|
|
79
|
+
"light": "SÁNG NHƯ CỦA ĐẢNG",
|
|
80
|
+
"dark": "Dark bủh lmao",
|
|
81
|
+
"parent folder": "Trở về thư mục trước",
|
|
82
|
+
"home": "Trang chủ",
|
|
83
|
+
"Continue": "Tiếp tục",
|
|
84
|
+
"Confirm": "Xác nhận",
|
|
85
|
+
"Don't": "Không",
|
|
86
|
+
"Warning": "Cảnh báo",
|
|
87
|
+
"Error": "Lỗi",
|
|
88
|
+
"Info": "Thông tin",
|
|
89
|
+
"Unauthorized": "Ko có quyền",
|
|
90
|
+
"Forbidden": "Thư mục / file này CẤM vào",
|
|
91
|
+
"Not found": "KO thấy",
|
|
92
|
+
"Server error": "Lỗi vật lý (server)",
|
|
93
|
+
"Upload": "Up",
|
|
94
|
+
"upload_concluded": "Tải lên đã kết thúc:",
|
|
95
|
+
"upload_finished": "{n} thành công ({size})",
|
|
96
|
+
"upload_errors": "{n} thất bại",
|
|
97
|
+
"upload_file_rejected": "Một số file server không chấp nhận",
|
|
98
|
+
"download counter": "bộ đếm tải xuống",
|
|
99
|
+
"File menu": "File menu",
|
|
100
|
+
"Folder menu": "Folder menu",
|
|
101
|
+
"Name": "Tên",
|
|
102
|
+
"file_open": "Mở (ngay trình duyệt, ms ko hỗ trợ)",
|
|
103
|
+
"Download": "Tải về",
|
|
104
|
+
"Missing permission": "Thiếu quyền!",
|
|
105
|
+
"Reload": "Tải lại",
|
|
106
|
+
"Get list": "Lấy danh sách",
|
|
107
|
+
"Skip existing files": "Bỏ qua các tệp hiện có",
|
|
108
|
+
"Size": "Size",
|
|
109
|
+
"Timestamp": "Mốc thời gian",
|
|
110
|
+
"Show": "Hiện",
|
|
111
|
+
"Loading failed": "Load ko thành công",
|
|
112
|
+
"Rename": "Đổi tên",
|
|
113
|
+
"Operation successful": "Tiến trình thành công",
|
|
114
|
+
"Uploader": "Người đã upload"
|
|
115
|
+
}
|
|
116
|
+
}
|