hfs 3.3.4 → 3.4.0-alpha2
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/AccountsPage-CoiPofEv.js +4 -0
- package/admin/assets/ConfigFilePage-jUH2feqi.js +4 -0
- package/admin/assets/CustomHtmlPage-Pl_AJZrl.js +2 -0
- package/admin/assets/InternetPage-DIcAwhFk.js +6 -0
- package/admin/assets/LangPage-BwVY8QRD.js +2 -0
- package/admin/assets/LogsPage-CcjS12cP.js +3 -0
- package/admin/assets/MonitorPage-DMVFXyMe.js +2 -0
- package/admin/assets/OptionsPage-BB40ax9G.js +3 -0
- package/admin/assets/PluginsPage-CC2dINcb.js +1 -0
- package/admin/assets/icons-C_ux1zLA.js +1 -0
- package/admin/assets/index-BSSQOMG_.js +755 -0
- package/admin/assets/index-mI9kZlpb.css +1 -0
- package/admin/assets/routing-Be72yFmd.js +1 -0
- package/admin/index.html +2 -2
- package/central.json +100 -1
- package/frontend/assets/{dist-legacy-CnYHQXZ6.js → dist-legacy-D7Dg5w3L.js} +1 -1
- package/frontend/assets/index-legacy-CnazC3Dj.js +1 -0
- package/frontend/assets/{lib-legacy-3xYueNHt.js → lib-legacy-BxFHpdER.js} +1 -1
- package/frontend/assets/{sha512-legacy-Cl3f_PhN.js → sha512-legacy-C8xoQBnP.js} +1 -1
- package/frontend/index.html +1 -1
- package/npm-shrinkwrap.json +9 -9
- package/package.json +2 -2
- package/plugins/antibrute/plugin.js +62 -15
- package/src/acme.js +143 -50
- package/src/acmeConfig.js +43 -0
- package/src/acmeDns.js +285 -0
- package/src/admin-langs/embedded.js +33 -0
- package/src/admin-langs/hfs-admin-lang-ar.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-bg.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-de.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-el.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-en.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-es.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-fi.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-fr.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-hu.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-it.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-ja.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-ko.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-lt.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-ms.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-nl.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-pl.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-pt-br.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-ro.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-ru.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-sr-latn.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-sr.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-th.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-tr.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-uk.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-vi.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-zh-hant.json +1149 -0
- package/src/admin-langs/hfs-admin-lang-zh.json +1149 -0
- package/src/adminApis.js +2 -2
- package/src/adminLang.js +51 -0
- package/src/api.auth.js +1 -1
- package/src/api.lang.js +22 -13
- package/src/api.log.js +5 -3
- package/src/api.net.js +20 -3
- package/src/api.plugins.js +53 -19
- package/src/api.vfs.js +3 -2
- package/src/argv.js +4 -0
- package/src/auth.js +13 -9
- package/src/basicWeb.js +6 -2
- package/src/block.js +1 -1
- package/src/config.js +1 -0
- package/src/connections.js +4 -7
- package/src/consoleLog.js +4 -0
- package/src/const.js +1 -1
- package/src/cross-const.js +8 -6
- package/src/cross.js +16 -2
- package/src/customHtml.js +3 -2
- package/src/frontEndApis.js +44 -7
- package/src/github.js +6 -37
- package/src/i18n.js +16 -4
- package/src/index.js +4 -3
- package/src/lang.js +21 -9
- package/src/langs/embedded.js +3 -2
- package/src/langs/hfs-lang-ar.json +7 -2
- package/src/langs/hfs-lang-bg.json +7 -2
- package/src/langs/hfs-lang-de.json +7 -2
- package/src/langs/hfs-lang-el.json +7 -2
- package/src/langs/hfs-lang-en.json +189 -0
- package/src/langs/hfs-lang-es.json +9 -4
- package/src/langs/hfs-lang-fi.json +8 -3
- package/src/langs/hfs-lang-fr.json +12 -7
- package/src/langs/hfs-lang-hu.json +7 -2
- package/src/langs/hfs-lang-it.json +11 -5
- package/src/langs/hfs-lang-ja.json +7 -2
- package/src/langs/hfs-lang-ko.json +7 -2
- package/src/langs/hfs-lang-lt.json +7 -2
- package/src/langs/hfs-lang-ms.json +9 -2
- package/src/langs/hfs-lang-nl.json +7 -2
- package/src/langs/hfs-lang-pl.json +7 -2
- package/src/langs/hfs-lang-pt-br.json +9 -4
- package/src/langs/hfs-lang-ro.json +7 -2
- package/src/langs/hfs-lang-ru.json +9 -4
- package/src/langs/hfs-lang-sr-latn.json +7 -2
- package/src/langs/hfs-lang-sr.json +7 -2
- package/src/langs/hfs-lang-th.json +8 -3
- package/src/langs/hfs-lang-tr.json +8 -3
- package/src/langs/hfs-lang-uk.json +16 -11
- package/src/langs/hfs-lang-vi.json +7 -2
- package/src/langs/hfs-lang-zh-hant.json +189 -0
- package/src/langs/hfs-lang-zh.json +97 -95
- package/src/listen.js +6 -3
- package/src/log.js +7 -1
- package/src/middlewares.js +87 -31
- package/src/multipartUpload.js +21 -0
- package/src/perm.js +38 -20
- package/src/pluginCatalog.js +66 -0
- package/src/pluginUsage.js +64 -0
- package/src/plugins.js +14 -2
- package/src/roots.js +22 -13
- package/src/serveFile.js +28 -11
- package/src/serveGuiAndSharedFiles.js +6 -6
- package/src/serveGuiFiles.js +7 -4
- package/src/update.js +51 -18
- package/src/upload.js +49 -8
- package/src/util-http.js +31 -5
- package/src/vfs.js +93 -4
- package/src/webdav.js +14 -8
- package/admin/assets/AccountsPage-CnZGcUox.js +0 -6
- package/admin/assets/ArrayField-F7fpCJIv.js +0 -2
- package/admin/assets/ConfigFilePage-CEgZ8Wq4.js +0 -4
- package/admin/assets/CustomHtmlPage-DDUNxF1H.js +0 -2
- package/admin/assets/DataTable-D_TeYxvk.js +0 -119
- package/admin/assets/DateTimeField-CsIdkTqz.js +0 -1
- package/admin/assets/EventManager--HiXIAY0.js +0 -1
- package/admin/assets/FileField-HsDCdr5S.js +0 -117
- package/admin/assets/InternetPage-DDwKrXJH.js +0 -8
- package/admin/assets/LangPage-Dd8hi_9K.js +0 -2
- package/admin/assets/LogsPage-BcPfugNY.js +0 -4
- package/admin/assets/MenuButton-cuehhVig.js +0 -1
- package/admin/assets/MonitorPage-Bre9d6MA.js +0 -2
- package/admin/assets/OptionsPage-Dd_cRDf4.js +0 -3
- package/admin/assets/PluginsPage-DJiseD4G.js +0 -1
- package/admin/assets/Tabs-C87E85Fh.js +0 -1
- package/admin/assets/TextEditor-BeS-mR2I.css +0 -1
- package/admin/assets/TextEditor-Cr0VI9Xi.js +0 -34
- package/admin/assets/VfsPathField-D1BkfhAM.js +0 -1
- package/admin/assets/agentIcons-CDoUTPUC.js +0 -1
- package/admin/assets/baseUrl-CnrV7Huu.js +0 -2
- package/admin/assets/icons-DJJYoK9E.js +0 -1
- package/admin/assets/index-11n5z0Ez.css +0 -1
- package/admin/assets/index-DwXlUHAs.js +0 -477
- package/admin/assets/routing-BQpoUdjq.js +0 -1
- package/frontend/assets/index-legacy-JYULclbY.js +0 -1
- package/src/langs/hfs-lang-zh-tw.json +0 -183
package/src/cross.js
CHANGED
|
@@ -77,6 +77,7 @@ exports.xlate = xlate;
|
|
|
77
77
|
exports.normalizeHost = normalizeHost;
|
|
78
78
|
exports.isIpLocalHost = isIpLocalHost;
|
|
79
79
|
exports.isIpLan = isIpLan;
|
|
80
|
+
exports.normalizeIp = normalizeIp;
|
|
80
81
|
exports.ipForUrl = ipForUrl;
|
|
81
82
|
exports.escapeHTML = escapeHTML;
|
|
82
83
|
exports.promiseBestEffort = promiseBestEffort;
|
|
@@ -142,7 +143,7 @@ exports.defaultPerms = {
|
|
|
142
143
|
};
|
|
143
144
|
exports.PERM_KEYS = typedKeys(exports.defaultPerms);
|
|
144
145
|
exports.VFS_STORED_KEYS = ['name', 'source', 'masks', 'default', 'accept', 'rename',
|
|
145
|
-
'mime', 'url', 'target', 'comment', 'icon', 'order', 'see_without_probing', 'children', ...exports.PERM_KEYS];
|
|
146
|
+
'mime', 'url', 'target', 'comment', 'icon', 'order', 'gui_asset', 'see_without_probing', 'children', ...exports.PERM_KEYS];
|
|
146
147
|
function isWhoObject(v) {
|
|
147
148
|
return v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
148
149
|
}
|
|
@@ -460,7 +461,20 @@ function isIpLocalHost(ip) {
|
|
|
460
461
|
return ip === '::1' || /^(?:::ffff:)?127\.0\.0\.1$/i.test(ip);
|
|
461
462
|
}
|
|
462
463
|
function isIpLan(ip) {
|
|
463
|
-
return /^(?:10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|
|
|
464
|
+
return /^(?:10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|169\.254\.|f[cd][\da-f]{2}:|fe[89ab][\da-f]:)/i.test(normalizeIp(ip));
|
|
465
|
+
}
|
|
466
|
+
function normalizeIp(ip) {
|
|
467
|
+
// proxy headers may contain invalid addresses; do not interpret URL paths or credentials as an IP
|
|
468
|
+
if (!/^[\da-f:.\[\]]+$/i.test(ip))
|
|
469
|
+
return ip;
|
|
470
|
+
// URL canonicalizes IPv6 and alternate IPv4 spellings before matching
|
|
471
|
+
const host = try_(() => new URL(`http://${ip.includes(':') && !ip.startsWith('[') ? `[${ip}]` : ip}`).hostname) || ip;
|
|
472
|
+
const bare = host.startsWith('[') ? host.slice(1, -1) : host;
|
|
473
|
+
if (bare.startsWith('::ffff:')) {
|
|
474
|
+
const words = bare.slice(7).split(':').map(x => parseInt(x, 16));
|
|
475
|
+
return words.flatMap(x => [x >> 8, x & 255]).join('.');
|
|
476
|
+
}
|
|
477
|
+
return bare;
|
|
464
478
|
}
|
|
465
479
|
function ipForUrl(ip) {
|
|
466
480
|
if (ip.startsWith('['))
|
package/src/customHtml.js
CHANGED
|
@@ -14,8 +14,9 @@ const config_1 = require("./config");
|
|
|
14
14
|
const plugins_1 = require("./plugins");
|
|
15
15
|
const lodash_1 = __importDefault(require("lodash"));
|
|
16
16
|
const FILE = 'custom.html';
|
|
17
|
-
exports.customHtmlSections = ['style', 'script', 'beforeHeader', 'afterHeader', 'afterMenuBar',
|
|
18
|
-
'footer', 'top', 'bottom', 'afterEntryName', 'beforeLogin', 'unauthorized', 'htmlHead', 'userPanelAfterInfo'
|
|
17
|
+
exports.customHtmlSections = ['style', 'script', 'beforeHeader', 'afterHeader', 'afterMenuBar',
|
|
18
|
+
'footer', 'top', 'bottom', 'afterEntryName', 'beforeLogin', 'unauthorized', 'htmlHead', 'userPanelAfterInfo',
|
|
19
|
+
'afterList', 'beforeOptions', 'afterOptions'];
|
|
19
20
|
exports.customHtml = watchLoadCustomHtml();
|
|
20
21
|
exports.disableCustomHtml = (0, config_1.defineConfig)(misc_1.CFG.disable_custom_html, false);
|
|
21
22
|
function watchLoadCustomHtml(folder = '') {
|
package/src/frontEndApis.js
CHANGED
|
@@ -19,6 +19,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
19
19
|
const promises_1 = require("fs/promises");
|
|
20
20
|
const path_1 = require("path");
|
|
21
21
|
const upload_1 = require("./upload");
|
|
22
|
+
const serveFile_1 = require("./serveFile");
|
|
22
23
|
const misc_1 = require("./misc");
|
|
23
24
|
const uploadOwners_1 = require("./uploadOwners");
|
|
24
25
|
const config_1 = require("./config");
|
|
@@ -59,10 +60,21 @@ exports.frontEndApis = {
|
|
|
59
60
|
return;
|
|
60
61
|
if (!isAdmin)
|
|
61
62
|
upload = lodash_1.default.omit(upload, 'ip');
|
|
62
|
-
return { upload };
|
|
63
|
+
return { upload, activeContent: isAdmin && (0, serveFile_1.isActiveContentMime)((0, serveFile_1.getNodeMime)(node)) };
|
|
63
64
|
}))
|
|
64
65
|
};
|
|
65
66
|
},
|
|
67
|
+
async set_upload_approved({ uri, approved }, ctx) {
|
|
68
|
+
(0, misc_1.apiAssertTypes)({ string: { uri }, boolean: { approved } });
|
|
69
|
+
if (!(0, adminApis_1.ctxAdminAccess)(ctx))
|
|
70
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED);
|
|
71
|
+
const node = await (0, vfs_1.urlToNode)(uri, ctx);
|
|
72
|
+
if (!node?.source)
|
|
73
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
|
|
74
|
+
if (!(0, serveFile_1.isActiveContentMime)((0, serveFile_1.getNodeMime)(node)))
|
|
75
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST);
|
|
76
|
+
return await (0, upload_1.setUploadApproved)(node.source, approved) ? {} : new apiMiddleware_1.ApiError(const_1.HTTP_FAILED_DEPENDENCY);
|
|
77
|
+
},
|
|
66
78
|
async create_folder({ uri, name }, ctx) {
|
|
67
79
|
(0, misc_1.apiAssertTypes)({ string: { uri, name } });
|
|
68
80
|
try {
|
|
@@ -115,10 +127,24 @@ exports.frontEndApis = {
|
|
|
115
127
|
return moveFiles(uri_from, uri_to, ctx);
|
|
116
128
|
},
|
|
117
129
|
async copy_files({ uri_from, uri_to }, ctx) {
|
|
118
|
-
return moveFiles(uri_from, uri_to, ctx, (srcNode, dest) =>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
130
|
+
return moveFiles(uri_from, uri_to, ctx, async (srcNode, dest) => {
|
|
131
|
+
const err = (0, vfs_1.statusCodeForMissingPerm)(srcNode, 'can_read', ctx);
|
|
132
|
+
if (err)
|
|
133
|
+
return err;
|
|
134
|
+
const upload = await (0, upload_1.getUploadMeta)(srcNode.source);
|
|
135
|
+
try {
|
|
136
|
+
return await (0, upload_1.whileUploadMetaPending)(dest, async () => {
|
|
137
|
+
await (0, promises_1.copyFile)(srcNode.source, dest, fs_1.default.constants.COPYFILE_EXCL | fs_1.default.constants.COPYFILE_FICLONE);
|
|
138
|
+
if (upload && !await (0, upload_1.saveUploadMeta)(dest, upload)) {
|
|
139
|
+
await (0, promises_1.unlink)(dest);
|
|
140
|
+
return const_1.HTTP_SERVER_ERROR;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
145
|
+
return e.code || String(e);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
122
148
|
},
|
|
123
149
|
async comment({ uri, comment }, ctx) {
|
|
124
150
|
(0, misc_1.apiAssertTypes)({ string: { uri, comment } });
|
|
@@ -197,6 +223,8 @@ async function moveFiles(uri_from, uri_to, ctx, override) {
|
|
|
197
223
|
const src = srcNode?.source;
|
|
198
224
|
if (!src)
|
|
199
225
|
return const_1.HTTP_NOT_FOUND;
|
|
226
|
+
if ((0, upload_1.isUploading)(src))
|
|
227
|
+
return const_1.HTTP_CONFLICT;
|
|
200
228
|
if (!override && (0, webdav_1.isWebdavLocked)(srcNode.vfsPath, ctx))
|
|
201
229
|
return ctx.status;
|
|
202
230
|
const destName = (0, path_1.basename)(src);
|
|
@@ -212,12 +240,19 @@ async function moveFiles(uri_from, uri_to, ctx, override) {
|
|
|
212
240
|
return ctx.status;
|
|
213
241
|
if (lodash_1.default.isFunction(override))
|
|
214
242
|
return override?.(srcNode, dest);
|
|
243
|
+
const upload = await (0, upload_1.getUploadMeta)(src);
|
|
215
244
|
return (0, vfs_1.statusCodeForMissingPerm)(srcNode, 'can_delete', ctx)
|
|
216
245
|
|| (0, promises_1.rename)(src, dest).catch(async (e) => {
|
|
217
246
|
if (e.code !== 'EXDEV')
|
|
218
247
|
throw e; // exdev = different drive
|
|
219
|
-
await (0,
|
|
220
|
-
|
|
248
|
+
await (0, upload_1.whileUploadMetaPending)(dest, async () => {
|
|
249
|
+
await (0, promises_1.copyFile)(src, dest);
|
|
250
|
+
if (upload && !await (0, upload_1.saveUploadMeta)(dest, upload)) {
|
|
251
|
+
await (0, promises_1.unlink)(dest);
|
|
252
|
+
throw Error("couldn't move upload metadata");
|
|
253
|
+
}
|
|
254
|
+
await (0, promises_1.unlink)(src);
|
|
255
|
+
});
|
|
221
256
|
}).then(() => (0, misc_1.moveStoredFileAttrs)(src, dest))
|
|
222
257
|
.then(() => (0, uploadOwners_1.moveUploadOwner)(srcNode.vfsPath, destUri, dest))
|
|
223
258
|
.catch(e => e.code || String(e));
|
|
@@ -227,6 +262,8 @@ async function moveFiles(uri_from, uri_to, ctx, override) {
|
|
|
227
262
|
async function requestedRename(node, newName, ctx) {
|
|
228
263
|
if (!node)
|
|
229
264
|
throw new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
|
|
265
|
+
if (node.source && (0, upload_1.isUploading)(node.source))
|
|
266
|
+
throw new apiMiddleware_1.ApiError(const_1.HTTP_CONFLICT);
|
|
230
267
|
// requestedRename is exported, so keep disk rename confinement here even when callers pre-validate
|
|
231
268
|
if (!(0, util_files_1.isValidFileName)(newName))
|
|
232
269
|
throw new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST);
|
package/src/github.js
CHANGED
|
@@ -12,7 +12,6 @@ exports.readOnlinePlugin = readOnlinePlugin;
|
|
|
12
12
|
exports.readOnlineCompatiblePlugin = readOnlineCompatiblePlugin;
|
|
13
13
|
exports.getFolder2repo = getFolder2repo;
|
|
14
14
|
exports.apiGithubPaginated = apiGithubPaginated;
|
|
15
|
-
exports.searchPlugins = searchPlugins;
|
|
16
15
|
const events_1 = __importDefault(require("./events"));
|
|
17
16
|
const misc_1 = require("./misc");
|
|
18
17
|
const plugins_1 = require("./plugins");
|
|
@@ -213,7 +212,7 @@ async function apiGithub(uri) {
|
|
|
213
212
|
: e;
|
|
214
213
|
});
|
|
215
214
|
}
|
|
216
|
-
async function* apiGithubPaginated(uri) {
|
|
215
|
+
async function* apiGithubPaginated(uri, { requireComplete = false } = {}) {
|
|
217
216
|
uri += uri.includes('?') ? '&' : '?';
|
|
218
217
|
const PAGE_SIZE = 100;
|
|
219
218
|
let page = 1;
|
|
@@ -221,6 +220,8 @@ async function* apiGithubPaginated(uri) {
|
|
|
221
220
|
try {
|
|
222
221
|
while (1) {
|
|
223
222
|
const res = await apiGithub(uri + `page=${page++}&per_page=${PAGE_SIZE}`);
|
|
223
|
+
if (requireComplete && res.incomplete_results)
|
|
224
|
+
throw Error("Incomplete GitHub search results");
|
|
224
225
|
const a = res.items || res; // "search/repositories" returns an object, while "releases" returns simply an array
|
|
225
226
|
for (const x of a)
|
|
226
227
|
yield x;
|
|
@@ -231,47 +232,13 @@ async function* apiGithubPaginated(uri) {
|
|
|
231
232
|
}
|
|
232
233
|
}
|
|
233
234
|
catch (e) {
|
|
234
|
-
if (e.message !== '422') // for some strange reason github api is returning this error if we search repos for a missing user, instead of empty set
|
|
235
|
+
if (requireComplete || e.message !== '422') // for some strange reason github api is returning this error if we search repos for a missing user, instead of empty set
|
|
235
236
|
throw e;
|
|
236
237
|
}
|
|
237
238
|
}
|
|
238
239
|
async function isPluginBlacklisted(repo) {
|
|
239
240
|
return (0, exports.getProjectInfo)().then(x => x?.repo_blacklist?.[repo]?.message || '', () => undefined);
|
|
240
241
|
}
|
|
241
|
-
async function searchPlugins(text = '', { skipRepos = [''] } = {}) {
|
|
242
|
-
const seen = new Set();
|
|
243
|
-
return new misc_1.AsapStream(pluginPromises());
|
|
244
|
-
async function* pluginPromises() {
|
|
245
|
-
// github doesn't allow complex search, so we have to do it multiple times and merge the results
|
|
246
|
-
const searches = [
|
|
247
|
-
...text.split(' ').filter(Boolean).slice(0, 2).map(x => 'user:' + encodeURI(x)), // first 2 words can be the author of the plugin
|
|
248
|
-
encodeURI(text), // search elsewhere, and results after the author search
|
|
249
|
-
];
|
|
250
|
-
for (const term of searches) {
|
|
251
|
-
for await (const it of apiGithubPaginated(`search/repositories?q=topic:hfs-plugin+${term}`)) {
|
|
252
|
-
const repo = it.full_name;
|
|
253
|
-
if (!repo || seen.has(repo)) // avoid duplicates, as we search multiple times
|
|
254
|
-
continue;
|
|
255
|
-
seen.add(repo);
|
|
256
|
-
if (skipRepos.includes(repo))
|
|
257
|
-
continue;
|
|
258
|
-
yield (async () => {
|
|
259
|
-
if (await isPluginBlacklisted(repo))
|
|
260
|
-
return;
|
|
261
|
-
const pl = await readOnlineCompatiblePlugin(repo, it.default_branch).catch(() => undefined);
|
|
262
|
-
if (!pl)
|
|
263
|
-
return;
|
|
264
|
-
Object.assign(pl, {
|
|
265
|
-
repo,
|
|
266
|
-
downloading: exports.downloading[repo],
|
|
267
|
-
license: it.license?.spdx_id,
|
|
268
|
-
}, lodash_1.default.pick(it, ['pushed_at', 'stargazers_count', 'default_branch']));
|
|
269
|
-
return pl;
|
|
270
|
-
})();
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
242
|
persistence_1.storedMap.ready().then(() => persistence_1.storedMap.del('alerts')); // remove legacy
|
|
276
243
|
const cachedCentralInfo = persistence_1.storedMap.singleSync('cachedCentralInfo', ''); // persisting it could also be useful for no-internet instances, so that you can provide a fresher copy
|
|
277
244
|
exports.blacklistedInstalledPlugins = [];
|
|
@@ -292,6 +259,8 @@ exports.getProjectInfo = (0, misc_1.debounceAsync)(async () => {
|
|
|
292
259
|
}
|
|
293
260
|
else
|
|
294
261
|
obj = { ...cachedCentralInfo.get() || JSON.parse(builtInJson) }; // fall back to built-in
|
|
262
|
+
// older catalogs predate DNS providers; an explicit empty list still disables the built-ins
|
|
263
|
+
obj.acmeDns ??= JSON.parse(builtInJson).acmeDns;
|
|
295
264
|
// merge byVersions info in the main object but collect alerts separately to preserve multiple instances
|
|
296
265
|
const newAlerts = [obj.alert];
|
|
297
266
|
for (const [ver, more] of Object.entries((0, misc_1.popKey)(obj, 'byVersion') || {}))
|
package/src/i18n.js
CHANGED
|
@@ -37,12 +37,21 @@ function i18nFromTranslations(translations, embedded = 'en') {
|
|
|
37
37
|
let selectedLang = ''; // keep track of where we find the translation
|
|
38
38
|
const { embedded } = state;
|
|
39
39
|
const langs = Object.keys(state.translations);
|
|
40
|
-
|
|
40
|
+
const english = state.translations[embedded]?.translate || {};
|
|
41
|
+
for (let key of keys) {
|
|
42
|
+
const originalKey = key;
|
|
43
|
+
if (!(key in english))
|
|
44
|
+
key = Object.keys(english).find(k => english[k] === key) || key; // support extensions still passing English text
|
|
45
|
+
const legacyKey = english[key] === key ? undefined : english[key];
|
|
41
46
|
for (const lang of searchLangs)
|
|
42
|
-
if (found = state.translations[selectedLang = lang]?.translate?.[key]
|
|
47
|
+
if (found = state.translations[selectedLang = lang]?.translate?.[key]
|
|
48
|
+
|| legacyKey && state.translations[selectedLang = lang]?.translate?.[legacyKey])
|
|
43
49
|
break;
|
|
44
50
|
if (found)
|
|
45
51
|
break;
|
|
52
|
+
if (!fallback && english[key])
|
|
53
|
+
fallback = english[key];
|
|
54
|
+
key = originalKey;
|
|
46
55
|
if (!warns.has(key) && langs.length && langs[0] !== embedded) {
|
|
47
56
|
warns.add(key);
|
|
48
57
|
console.debug("i18n miss:", key);
|
|
@@ -85,7 +94,7 @@ function i18nFromTranslations(translations, embedded = 'en') {
|
|
|
85
94
|
}
|
|
86
95
|
return pick(other);
|
|
87
96
|
function pick(s) {
|
|
88
|
-
return s.
|
|
97
|
+
return s.replaceAll('#', String(v)).replace(/\{(\w+)\}/g, (_, key) => params[key] ?? '');
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
100
|
}
|
|
@@ -118,7 +127,10 @@ function i18nFromTranslations(translations, embedded = 'en') {
|
|
|
118
127
|
t,
|
|
119
128
|
state,
|
|
120
129
|
getLangs,
|
|
121
|
-
i18nWrapperProps: () =>
|
|
130
|
+
i18nWrapperProps: () => {
|
|
131
|
+
const lang = state.disabled ? state.embedded : getLangs()[0] || state.embedded;
|
|
132
|
+
return { lang, dir: lang === 'ar' ? 'rtl' : 'ltr' };
|
|
133
|
+
},
|
|
122
134
|
useI18N() {
|
|
123
135
|
(0, valtio_1.useSnapshot)(state);
|
|
124
136
|
return { t };
|
package/src/index.js
CHANGED
|
@@ -34,6 +34,7 @@ const roots_1 = require("./roots");
|
|
|
34
34
|
const events_1 = __importDefault(require("./events"));
|
|
35
35
|
const ips_1 = require("./ips");
|
|
36
36
|
require("./outboundProxy");
|
|
37
|
+
require("./pluginUsage");
|
|
37
38
|
(0, assert_1.ok)(lodash_1.default.intersection(Object.keys(frontEndApis_1.frontEndApis), Object.keys(adminApis_1.adminApis)).length === 0); // they share same endpoints, don't clash
|
|
38
39
|
if (new config_1.Version(process.versions.node).olderThan('18.15.0')) {
|
|
39
40
|
console.error("Node.js 18.15+ is required, please update");
|
|
@@ -53,11 +54,11 @@ exports.app.use(middlewares_1.sessionMiddleware)
|
|
|
53
54
|
.use(middlewares_1.prepareState)
|
|
54
55
|
.use(ips_1.trackIpsMw)
|
|
55
56
|
.use(middlewares_1.gzipper)
|
|
56
|
-
.use(
|
|
57
|
-
.use(middlewares_1.headRequests)
|
|
58
|
-
.use(roots_1.rootsMiddleware)
|
|
57
|
+
.use(roots_1.rootsHostGuard)
|
|
59
58
|
.use(log_1.logMw)
|
|
60
59
|
.use(middlewares_1.someSecurity)
|
|
60
|
+
.use(middlewares_1.paramsDecoder) // must be done before plugins, so they can manipulate params
|
|
61
|
+
.use(roots_1.rootsMiddleware)
|
|
61
62
|
.use(throttler_1.throttler)
|
|
62
63
|
.use(plugins_1.pluginsMiddleware)
|
|
63
64
|
.use((0, koa_mount_1.default)(const_1.API_URI, (0, apiMiddleware_1.apiMiddleware)({ ...frontEndApis_1.frontEndApis, ...adminApis_1.adminApis })))
|
package/src/lang.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.normalizeLangCode = normalizeLangCode;
|
|
7
|
+
exports.langCodeForLookup = langCodeForLookup;
|
|
7
8
|
exports.code2file = code2file;
|
|
8
9
|
exports.file2code = file2code;
|
|
9
10
|
exports.getLangData = getLangData;
|
|
@@ -17,17 +18,19 @@ const const_1 = require("./const");
|
|
|
17
18
|
const plugins_1 = require("./plugins");
|
|
18
19
|
const path_1 = require("path");
|
|
19
20
|
const lodash_1 = __importDefault(require("lodash"));
|
|
20
|
-
const PREFIX = 'hfs-lang-';
|
|
21
21
|
const SUFFIX = '.json';
|
|
22
22
|
function normalizeLangCode(code) {
|
|
23
23
|
code = code.toLowerCase().split(';', 1)[0].trim();
|
|
24
24
|
return /^[a-z]{2,3}(-[a-z0-9]{2,8})*$/.test(code) ? code : '';
|
|
25
25
|
}
|
|
26
|
-
function
|
|
27
|
-
return
|
|
26
|
+
function langCodeForLookup(code) {
|
|
27
|
+
return ['zh-tw', 'zh-hk', 'zh-mo'].includes(code) ? 'zh-hant' : code;
|
|
28
28
|
}
|
|
29
|
-
function
|
|
30
|
-
return
|
|
29
|
+
function code2file(code, admin = false) {
|
|
30
|
+
return (admin ? 'hfs-admin-lang-' : 'hfs-lang-') + code.toLowerCase() + SUFFIX;
|
|
31
|
+
}
|
|
32
|
+
function file2code(fn, admin = false) {
|
|
33
|
+
return fn.replace(admin ? 'hfs-admin-lang-' : 'hfs-lang-', '').replace(SUFFIX, '');
|
|
31
34
|
}
|
|
32
35
|
const cache = (0, expiringCache_1.expiringCache)(3_000); // 3 seconds for both a good dx and acceptable performance
|
|
33
36
|
async function getLangData(ctxOrLangCsv) {
|
|
@@ -40,12 +43,14 @@ async function getLangData(ctxOrLangCsv) {
|
|
|
40
43
|
}
|
|
41
44
|
const csv = ctxOrLangCsv.toLowerCase();
|
|
42
45
|
return cache.try(csv, async () => {
|
|
43
|
-
const langs = csv.split(',').map(normalizeLangCode).filter(Boolean);
|
|
46
|
+
const langs = csv.split(',').map(normalizeLangCode).map(langCodeForLookup).filter(Boolean);
|
|
47
|
+
if (!langs.includes(const_1.EMBEDDED_LANGUAGE))
|
|
48
|
+
langs.push(const_1.EMBEDDED_LANGUAGE);
|
|
44
49
|
const ret = {};
|
|
45
50
|
let i = 0;
|
|
46
51
|
while (i < langs.length) {
|
|
47
52
|
let k = langs[i] || ''; // shut up ts
|
|
48
|
-
if (!k
|
|
53
|
+
if (!k)
|
|
49
54
|
break;
|
|
50
55
|
const fn = code2file(k);
|
|
51
56
|
try {
|
|
@@ -75,15 +80,22 @@ async function getLangData(ctxOrLangCsv) {
|
|
|
75
80
|
let forceLangData;
|
|
76
81
|
let undo;
|
|
77
82
|
(0, config_1.defineConfig)(misc_1.CFG.force_lang, '', v => {
|
|
83
|
+
v = langCodeForLookup(v);
|
|
78
84
|
undo?.();
|
|
79
85
|
if (!v)
|
|
80
86
|
return forceLangData = undefined;
|
|
81
87
|
const translation = embedded_1.default[v];
|
|
82
|
-
forceLangData = {
|
|
88
|
+
forceLangData = {
|
|
89
|
+
[v]: translation,
|
|
90
|
+
...v === const_1.EMBEDDED_LANGUAGE ? {} : { [const_1.EMBEDDED_LANGUAGE]: embedded_1.default.en },
|
|
91
|
+
};
|
|
83
92
|
if (v === const_1.EMBEDDED_LANGUAGE)
|
|
84
93
|
return;
|
|
85
94
|
const res = (0, watchLoad_1.watchLoad)(code2file(v), data => {
|
|
86
|
-
forceLangData = {
|
|
95
|
+
forceLangData = {
|
|
96
|
+
[v]: (0, misc_1.tryJson)(data) || translation,
|
|
97
|
+
[const_1.EMBEDDED_LANGUAGE]: embedded_1.default.en,
|
|
98
|
+
};
|
|
87
99
|
});
|
|
88
100
|
undo = res.unwatch;
|
|
89
101
|
});
|
package/src/langs/embedded.js
CHANGED
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const hfs_lang_en_json_1 = __importDefault(require("./hfs-lang-en.json"));
|
|
6
7
|
const hfs_lang_it_json_1 = __importDefault(require("./hfs-lang-it.json"));
|
|
7
8
|
const hfs_lang_zh_json_1 = __importDefault(require("./hfs-lang-zh.json"));
|
|
8
9
|
const hfs_lang_ru_json_1 = __importDefault(require("./hfs-lang-ru.json"));
|
|
@@ -11,7 +12,7 @@ const hfs_lang_sr_json_1 = __importDefault(require("./hfs-lang-sr.json"));
|
|
|
11
12
|
const hfs_lang_sr_latn_json_1 = __importDefault(require("./hfs-lang-sr-latn.json"));
|
|
12
13
|
const hfs_lang_ko_json_1 = __importDefault(require("./hfs-lang-ko.json"));
|
|
13
14
|
const hfs_lang_ms_json_1 = __importDefault(require("./hfs-lang-ms.json"));
|
|
14
|
-
const
|
|
15
|
+
const hfs_lang_zh_hant_json_1 = __importDefault(require("./hfs-lang-zh-hant.json"));
|
|
15
16
|
const hfs_lang_fr_json_1 = __importDefault(require("./hfs-lang-fr.json"));
|
|
16
17
|
const hfs_lang_pl_json_1 = __importDefault(require("./hfs-lang-pl.json"));
|
|
17
18
|
const hfs_lang_pt_br_json_1 = __importDefault(require("./hfs-lang-pt-br.json"));
|
|
@@ -29,4 +30,4 @@ const hfs_lang_uk_json_1 = __importDefault(require("./hfs-lang-uk.json"));
|
|
|
29
30
|
const hfs_lang_ar_json_1 = __importDefault(require("./hfs-lang-ar.json"));
|
|
30
31
|
const hfs_lang_lt_json_1 = __importDefault(require("./hfs-lang-lt.json"));
|
|
31
32
|
const hfs_lang_bg_json_1 = __importDefault(require("./hfs-lang-bg.json"));
|
|
32
|
-
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, 'sr-latn': hfs_lang_sr_latn_json_1.default, ko: hfs_lang_ko_json_1.default, ms: hfs_lang_ms_json_1.default, 'zh-
|
|
33
|
+
exports.default = { en: hfs_lang_en_json_1.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, 'sr-latn': hfs_lang_sr_latn_json_1.default, ko: hfs_lang_ko_json_1.default, ms: hfs_lang_ms_json_1.default, 'zh-hant': hfs_lang_zh_hant_json_1.default, fr: hfs_lang_fr_json_1.default, pl: hfs_lang_pl_json_1.default, 'pt-br': hfs_lang_pt_br_json_1.default, vi: hfs_lang_vi_json_1.default, es: hfs_lang_es_json_1.default, nl: hfs_lang_nl_json_1.default, el: hfs_lang_el_json_1.default, de: hfs_lang_de_json_1.default, fi: hfs_lang_fi_json_1.default, hu: hfs_lang_hu_json_1.default, ja: hfs_lang_ja_json_1.default, ro: hfs_lang_ro_json_1.default, tr: hfs_lang_tr_json_1.default, th: hfs_lang_th_json_1.default, uk: hfs_lang_uk_json_1.default, ar: hfs_lang_ar_json_1.default, lt: hfs_lang_lt_json_1.default, bg: hfs_lang_bg_json_1.default };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Hussein M. Alghazal (hmg3099)",
|
|
3
3
|
"version": 1.0,
|
|
4
|
-
"hfs_version": "0.57.5",
|
|
5
4
|
"translate": {
|
|
6
5
|
"Select": "اختر",
|
|
7
6
|
"n_files": "{n,plural,one{# file} other{# files}}",
|
|
@@ -39,6 +38,7 @@
|
|
|
39
38
|
"Password": "كلمة المرور",
|
|
40
39
|
"login_untrusted": "تم إيقاف تسجيل الدخول: لا يمكن الوثوق بهوية الخادم",
|
|
41
40
|
"login_bad_credentials": "بيانات اعتماد غير صالحة",
|
|
41
|
+
"confirm_url_login": "يحاول هذا الرابط تسجيل دخولك باسم «{username}»",
|
|
42
42
|
"login_bad_cookies": "الكوكيز لا تعمل - فشل تسجيل الدخول",
|
|
43
43
|
"User panel": "لوحة المستخدم",
|
|
44
44
|
"Change password": "تغيير كلمة المرور",
|
|
@@ -110,6 +110,8 @@
|
|
|
110
110
|
"Timestamp": "الطابع الزمني",
|
|
111
111
|
"Show": "عرض",
|
|
112
112
|
"Loading failed": "فشل التحميل",
|
|
113
|
+
"Download limit reached": "تم بلوغ حد التنزيلات",
|
|
114
|
+
"Retry": "إعادة المحاولة",
|
|
113
115
|
"Rename": "إعادة تسمية",
|
|
114
116
|
"Tiles mode:": "وضع الشبكة:",
|
|
115
117
|
"off": "إيقاف",
|
|
@@ -178,6 +180,9 @@
|
|
|
178
180
|
"No": "لا",
|
|
179
181
|
"esc_again": "انقر على ESC ثانية لاغلاق",
|
|
180
182
|
"insufficient storage": "مساحة تخزين غير كافية",
|
|
181
|
-
"Account disabled": "تم تعطيل الحساب"
|
|
183
|
+
"Account disabled": "تم تعطيل الحساب",
|
|
184
|
+
"upload_name": "تحميل بالاسم الجديد",
|
|
185
|
+
"Uploading": "جارٍ التحميل",
|
|
186
|
+
"proxy_413": "تحقق من هذا الحد على الخادم الوكيل"
|
|
182
187
|
}
|
|
183
188
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Ангел Трънгалов",
|
|
3
3
|
"version": 1.0,
|
|
4
|
-
"hfs_version": "0.57.5",
|
|
5
4
|
"translate": {
|
|
6
5
|
"Select": "Избери",
|
|
7
6
|
"n_files": "{n,plural,one{# файл} other{# файлове}}",
|
|
@@ -39,6 +38,7 @@
|
|
|
39
38
|
"Password": "Парола",
|
|
40
39
|
"login_untrusted": "Вход отказан: самоличността на сървъра не е надеждна",
|
|
41
40
|
"login_bad_credentials": "Невалидни данни за вход",
|
|
41
|
+
"confirm_url_login": "Тази връзка се опитва да ви впише като „{username}“",
|
|
42
42
|
"login_bad_cookies": "Бисквитките не работят - вход неуспешен",
|
|
43
43
|
"User panel": "Панел на потребителя",
|
|
44
44
|
"Change password": "Смяна на парола",
|
|
@@ -108,6 +108,8 @@
|
|
|
108
108
|
"Timestamp": "Печат на време",
|
|
109
109
|
"Show": "Покажи",
|
|
110
110
|
"Loading failed": "Зареждането неуспешно",
|
|
111
|
+
"Download limit reached": "Достигнат е лимитът за изтегляния",
|
|
112
|
+
"Retry": "Опитай отново",
|
|
111
113
|
"Rename": "Преименувай",
|
|
112
114
|
"Tiles mode:": "Режим плочки:",
|
|
113
115
|
"off": "изкл.",
|
|
@@ -176,6 +178,9 @@
|
|
|
176
178
|
"No": "Не",
|
|
177
179
|
"esc_again": "Натиснете ESC два пъти за затваряне",
|
|
178
180
|
"insufficient storage": "недостатъчно пространство",
|
|
179
|
-
"Account disabled": "Акаунтът е деактивиран"
|
|
181
|
+
"Account disabled": "Акаунтът е деактивиран",
|
|
182
|
+
"upload_name": "Качване с ново име",
|
|
183
|
+
"Uploading": "Качване",
|
|
184
|
+
"proxy_413": "Проверете за това ограничение на прокси сървъра"
|
|
180
185
|
}
|
|
181
186
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Uwe Wennmann",
|
|
3
3
|
"version": 0.1,
|
|
4
|
-
"hfs_version": "0.57.5",
|
|
5
4
|
"translate": {
|
|
6
5
|
"Select": "Auswählen",
|
|
7
6
|
"n_files": "{n,plural,one{# Datei} other{# Dateien}}",
|
|
@@ -39,6 +38,7 @@
|
|
|
39
38
|
"Password": "Passwort",
|
|
40
39
|
"login_untrusted": "Anmeldung abgebrochen: Der Serveridentität kann nicht vertraut werden.",
|
|
41
40
|
"login_bad_credentials": "Ungültige Anmeldedaten",
|
|
41
|
+
"confirm_url_login": "Dieser Link versucht, Sie als „{username}“ anzumelden",
|
|
42
42
|
"login_bad_cookies": "Cookies funktionieren nicht - Anmeldung fehlgeschlagen",
|
|
43
43
|
"User panel": "Benutzer-Panel",
|
|
44
44
|
"Change password": "Das Passwort ändern.",
|
|
@@ -110,6 +110,8 @@
|
|
|
110
110
|
"Timestamp": "Zeitstempel",
|
|
111
111
|
"Show": "Anzeigen",
|
|
112
112
|
"Loading failed": "Laden fehlgeschlagen",
|
|
113
|
+
"Download limit reached": "Download-Limit erreicht",
|
|
114
|
+
"Retry": "Erneut versuchen",
|
|
113
115
|
"Rename": "Umbenennen",
|
|
114
116
|
"Tiles mode:": "Kachel-Modus:",
|
|
115
117
|
"off": "aus",
|
|
@@ -178,6 +180,9 @@
|
|
|
178
180
|
"No": "Nein",
|
|
179
181
|
"esc_again": "Drucken Sie ESC zwei Mal, um das Fenster zu schließen.",
|
|
180
182
|
"insufficient storage": "nicht genügend Speicherplatz",
|
|
181
|
-
"Account disabled": "Konto deaktiviert"
|
|
183
|
+
"Account disabled": "Konto deaktiviert",
|
|
184
|
+
"upload_name": "Mit neuem Namen hochladen",
|
|
185
|
+
"Uploading": "Hochladen",
|
|
186
|
+
"proxy_413": "Überprüfen Sie den Proxyserver auf dieses Limit"
|
|
182
187
|
}
|
|
183
188
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Konstantinos (konmaz)",
|
|
3
3
|
"version": 1.0,
|
|
4
|
-
"hfs_version": "0.57.5",
|
|
5
4
|
"translate": {
|
|
6
5
|
"Select": "Επιλογή",
|
|
7
6
|
"n_files": "{n,plural,one{# αρχείο} other{# αρχεία}}",
|
|
@@ -39,6 +38,7 @@
|
|
|
39
38
|
"Password": "Κωδικός πρόσβασης",
|
|
40
39
|
"login_untrusted": "Η σύνδεση ακυρώθηκε: δεν μπορεί να εμπιστευτείται την ταυτότητα του διακομιστή",
|
|
41
40
|
"login_bad_credentials": "Μη έγκυρα διαπιστευτήρια",
|
|
41
|
+
"confirm_url_login": "Αυτός ο σύνδεσμος προσπαθεί να σας συνδέσει ως «{username}»",
|
|
42
42
|
"login_bad_cookies": "Τα cookies δεν λειτουργούν - η σύνδεση απέτυχε",
|
|
43
43
|
"User panel": "Πίνακας χρήστη",
|
|
44
44
|
"Change password": "Αλλαγή κωδικού πρόσβασης",
|
|
@@ -110,6 +110,8 @@
|
|
|
110
110
|
"Timestamp": "Χρονική σήμανση",
|
|
111
111
|
"Show": "Εμφάνιση",
|
|
112
112
|
"Loading failed": "Η φόρτωση απέτυχε",
|
|
113
|
+
"Download limit reached": "Συμπληρώθηκε το όριο λήψεων",
|
|
114
|
+
"Retry": "Δοκιμή ξανά",
|
|
113
115
|
"Rename": "Μετονομασία",
|
|
114
116
|
"Tiles mode:": "Λειτουργία πλακιδίων:",
|
|
115
117
|
"off": "ανενεργό",
|
|
@@ -178,6 +180,9 @@
|
|
|
178
180
|
"No": "Οχι",
|
|
179
181
|
"esc_again": "Πατήστε ESC δυο φορές για να κλειστειτε",
|
|
180
182
|
"insufficient storage": "ανεπαρκής χώρος αποθήκευσης",
|
|
181
|
-
"Account disabled": "Ο λογαριασμός έχει απενεργοποιηθεί"
|
|
183
|
+
"Account disabled": "Ο λογαριασμός έχει απενεργοποιηθεί",
|
|
184
|
+
"upload_name": "Μεταφόρτωση με νέο όνομα",
|
|
185
|
+
"Uploading": "Μεταφόρτωση",
|
|
186
|
+
"proxy_413": "Ελέγξτε για αυτό το όριο στον διακομιστή μεσολάβησης"
|
|
182
187
|
}
|
|
183
188
|
}
|