hfs 0.46.1 → 0.47.0-alpha6
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 +4 -4
- package/admin/assets/{index-35f6e3dc.css → index-20dd43f3.css} +1 -1
- package/admin/assets/index-d55dfed9.js +518 -0
- package/{frontend/assets/sha512-d9635c9d.js → admin/assets/sha512-9867267f.js} +1 -1
- package/admin/index.html +2 -2
- package/frontend/assets/index-3a32a9b9.css +1 -0
- package/frontend/assets/index-ad78cbad.js +116 -0
- package/{admin/assets/sha512-3412b98f.js → frontend/assets/sha512-4c1cbf45.js} +1 -1
- package/frontend/fontello.css +5 -2
- package/frontend/fontello.woff2 +0 -0
- package/frontend/index.html +2 -3
- package/package.json +2 -2
- package/plugins/download-counter/plugin.js +15 -7
- package/plugins/download-counter/public/main.js +1 -1
- package/plugins/list-uploader/plugin.js +1 -1
- package/plugins/list-uploader/public/main.js +9 -10
- package/plugins/vhosting/plugin.js +5 -2
- package/src/QuickZipStream.js +3 -0
- package/src/adminApis.js +20 -5
- package/src/api.auth.js +0 -3
- package/src/api.file_list.js +3 -2
- package/src/api.monitor.js +36 -33
- package/src/api.vfs.js +37 -34
- package/src/apiMiddleware.js +44 -15
- package/src/commands.js +2 -2
- package/src/config.js +16 -13
- package/src/connections.js +3 -4
- package/src/consoleLog.js +17 -0
- package/src/const.js +4 -3
- package/src/frontEndApis.js +17 -10
- package/src/github.js +1 -1
- package/src/index.js +3 -1
- package/src/langs/embedded.js +3 -1
- package/src/langs/hfs-lang-es.json +118 -0
- package/src/langs/hfs-lang-it.json +7 -5
- package/src/langs/hfs-lang-nl.json +118 -0
- package/src/langs/hfs-lang-ru.json +3 -3
- package/src/langs/hfs-lang-zh.json +25 -5
- package/src/log.js +5 -3
- package/src/middlewares.js +2 -2
- package/src/misc.js +5 -1
- package/src/perm.js +1 -1
- package/src/serveFile.js +3 -1
- package/src/throttler.js +2 -1
- package/src/update.js +45 -7
- package/src/util-http.js +8 -3
- package/src/vfs.js +36 -12
- package/admin/assets/index-7f1741ba.js +0 -517
- package/frontend/assets/index-b49b8a16.js +0 -94
- package/frontend/assets/index-f2f8fd6b.css +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{g as OF,c as UF}from"./index-
|
|
1
|
+
import{g as OF,c as UF}from"./index-ad78cbad.js";function gF(sF,hF){for(var eF=0;eF<hF.length;eF++){const tF=hF[eF];if(typeof tF!="string"&&!Array.isArray(tF)){for(const w in tF)if(w!=="default"&&!(w in sF)){const lF=Object.getOwnPropertyDescriptor(tF,w);lF&&Object.defineProperty(sF,w,lF.get?lF:{enumerable:!0,get:()=>tF[w]})}}}return Object.freeze(Object.defineProperty(sF,Symbol.toStringTag,{value:"Module"}))}var dF={exports:{}};/*
|
|
2
2
|
* [js-sha512]{@link https://github.com/emn178/js-sha512}
|
|
3
3
|
*
|
|
4
4
|
* @version 0.8.0
|
package/frontend/fontello.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
@font-face {
|
|
2
2
|
font-family: 'fontello';
|
|
3
|
-
src: url('fontello.woff2?
|
|
3
|
+
src: url('fontello.woff2?44288867') format('woff2');
|
|
4
4
|
font-weight: normal;
|
|
5
5
|
font-style: normal;
|
|
6
6
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
|
11
11
|
@font-face {
|
|
12
12
|
font-family: 'fontello';
|
|
13
|
-
src: url('../font/fontello.svg?
|
|
13
|
+
src: url('../font/fontello.svg?44288867#fontello') format('svg');
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
*/
|
|
@@ -78,7 +78,10 @@
|
|
|
78
78
|
.fa-download:before { content: '\f02e'; } /* '' */
|
|
79
79
|
.fa-upload:before { content: '\f02f'; } /* '' */
|
|
80
80
|
.fa-filter:before { content: '\f0b0'; } /* '' */
|
|
81
|
+
.fa-zoom:before { content: '\f0b2'; } /* '' */
|
|
81
82
|
.fa-menu:before { content: '\f0c9'; } /* '' */
|
|
83
|
+
.fa-comment:before { content: '\f0e5'; } /* '' */
|
|
84
|
+
.fa-fullscreen:before { content: '\f108'; } /* '' */
|
|
82
85
|
.fa-quote:before { content: '\f10d'; } /* '' */
|
|
83
86
|
.fa-unlink:before { content: '\f127'; } /* '' */
|
|
84
87
|
.fa-archive:before { content: '\f1c6'; } /* '' */
|
package/frontend/fontello.woff2
CHANGED
|
Binary file
|
package/frontend/index.html
CHANGED
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0" />
|
|
6
6
|
<link href="/fontello.css" rel="stylesheet" />
|
|
7
|
-
<script>HFS={}</script>
|
|
8
7
|
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
-
<link rel="stylesheet" href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-ad78cbad.js"></script>
|
|
9
|
+
<link rel="stylesheet" href="/assets/index-3a32a9b9.css">
|
|
11
10
|
</head>
|
|
12
11
|
<body>
|
|
13
12
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hfs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0-alpha6",
|
|
4
4
|
"description": "HTTP File Server",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"file server",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"fast-glob": "^3.2.7",
|
|
69
69
|
"find-process": "^1.4.7",
|
|
70
70
|
"formidable": "^2.1.1",
|
|
71
|
-
"fs-x-attributes": "^1.0.
|
|
71
|
+
"fs-x-attributes": "^1.0.2",
|
|
72
72
|
"koa": "^2.13.4",
|
|
73
73
|
"koa-compress": "^5.1.0",
|
|
74
74
|
"koa-mount": "^4.0.0",
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
// other plugins can use ctx.state.download_counter_ignore to mark downloads that shouldn't be counted
|
|
2
2
|
|
|
3
3
|
exports.description = "Counts downloads for each file, and displays the total in the list or file menu"
|
|
4
|
-
exports.version =
|
|
5
|
-
exports.apiRequired = 8
|
|
4
|
+
exports.version = 5 // count files in archive
|
|
5
|
+
exports.apiRequired = 8.3
|
|
6
6
|
|
|
7
7
|
exports.config = {
|
|
8
8
|
where: { frontend: true, type: 'select', defaultValue: 'menu',
|
|
9
9
|
options: ['list', { value: 'menu', label: "file menu" }],
|
|
10
|
-
}
|
|
10
|
+
},
|
|
11
|
+
archives: { defaultValue: true, type: 'boolean', label: "Count files in zip/archives" },
|
|
11
12
|
}
|
|
12
13
|
exports.configDialog = {
|
|
13
14
|
sx: { maxWidth: '20em' },
|
|
@@ -45,10 +46,17 @@ exports.init = async api => {
|
|
|
45
46
|
unload: () => save.flush(), // we may have pending savings
|
|
46
47
|
middleware: (ctx) =>
|
|
47
48
|
() => { // execute after other middlewares are done
|
|
48
|
-
if (ctx.status >= 300 ||
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
if (ctx.status >= 300 || ctx.state.download_counter_ignore || ctx.state.includesLastByte === false) return
|
|
50
|
+
if (!(ctx.vfsNode || api.getConfig('archives') && ctx.state.archive)) return
|
|
51
|
+
ctx.state.completed.then(() => {
|
|
52
|
+
const key = uri2key(ctx.path)
|
|
53
|
+
const entries = ctx.vfsNode ? [key]
|
|
54
|
+
: ctx.state.originalStream?.getArchiveEntries?.().filter(x => x.at(-1) !== '/').map(x => key + uri2key(x))
|
|
55
|
+
if (!entries) return
|
|
56
|
+
for (const k of entries)
|
|
57
|
+
counters[k] = counters[k] + 1 || 1
|
|
58
|
+
save()
|
|
59
|
+
})
|
|
52
60
|
},
|
|
53
61
|
onDirEntry: ({ entry, listUri }) => {
|
|
54
62
|
const k = uri2key(listUri + entry.n)
|
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
"use strict";{
|
|
2
|
+
const { React } = HFS
|
|
2
3
|
const { display } = HFS.getPluginConfig()
|
|
3
4
|
|
|
4
5
|
HFS.onEvent('additionalEntryDetails', ({ entry }) =>
|
|
5
6
|
HFS.h(Uploader, entry))
|
|
6
7
|
|
|
7
|
-
const cache = {}
|
|
8
|
-
|
|
9
8
|
function Uploader({ uri }) {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const [freshData, error] = HFS.useApi(!cachedData && 'get_file_details', { uri: fullUri })
|
|
13
|
-
if (!cachedData)
|
|
14
|
-
cache[fullUri] = freshData || Boolean(error)
|
|
15
|
-
const data = freshData || cachedData
|
|
16
|
-
const text = HFS.React.useMemo(() => {
|
|
9
|
+
const { data } = HFS.useBatch(getDetails, uri)
|
|
10
|
+
const text = React.useMemo(() => {
|
|
17
11
|
if (!data || data === true) return ''
|
|
18
12
|
const { upload: x } = data
|
|
19
13
|
return !x ? ''
|
|
20
14
|
: display === 'user' ? x.username
|
|
21
15
|
: display === 'ip' || !x.username ? x.ip
|
|
22
16
|
: x.ip + ' (' + x.username + ')'
|
|
23
|
-
})
|
|
17
|
+
}, [data])
|
|
24
18
|
return text && HFS.h('span', { className: 'uploader', title: HFS.t`Uploader` },
|
|
25
19
|
HFS.hIcon('upload'), ' ', text, ' – ')
|
|
26
20
|
}
|
|
21
|
+
|
|
22
|
+
function getDetails(batched) {
|
|
23
|
+
return batched.length && HFS.apiCall('get_file_details', { uris: batched }).then(x => x.details)
|
|
24
|
+
}
|
|
25
|
+
|
|
27
26
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
exports.description = "If you want to have different home folders, based on domain"
|
|
2
|
-
exports.version = 3.
|
|
2
|
+
exports.version = 3.12
|
|
3
3
|
exports.apiRequired = 2 // 2 is for the config 'array'
|
|
4
4
|
|
|
5
5
|
exports.config = {
|
|
@@ -44,12 +44,15 @@ exports.init = api => {
|
|
|
44
44
|
let { root='' } = row
|
|
45
45
|
if (root.endsWith('/'))
|
|
46
46
|
root = root.slice(0, -1)
|
|
47
|
+
if (root && root[0] !== '/') // normalize
|
|
48
|
+
root = '/' + root
|
|
49
|
+
if (!root) return
|
|
47
50
|
if (!params)
|
|
48
51
|
ctx.path = root + ctx.path
|
|
49
52
|
else
|
|
50
53
|
for (const [k,v] of Object.entries(params))
|
|
51
54
|
if (k.startsWith('uri'))
|
|
52
|
-
params[k] = root + v
|
|
55
|
+
params[k] = Array.isArray(v) ? v.map(x => root + x) : root + v
|
|
53
56
|
}
|
|
54
57
|
}
|
|
55
58
|
}
|
package/src/QuickZipStream.js
CHANGED
package/src/adminApis.js
CHANGED
|
@@ -51,6 +51,7 @@ const util_1 = require("util");
|
|
|
51
51
|
const customHtml_1 = require("./customHtml");
|
|
52
52
|
const lodash_1 = __importDefault(require("lodash"));
|
|
53
53
|
const update_1 = require("./update");
|
|
54
|
+
const consoleLog_1 = require("./consoleLog");
|
|
54
55
|
exports.adminApis = {
|
|
55
56
|
...api_vfs_1.default,
|
|
56
57
|
...api_accounts_1.default,
|
|
@@ -73,8 +74,12 @@ exports.adminApis = {
|
|
|
73
74
|
return {};
|
|
74
75
|
},
|
|
75
76
|
get_config: config_1.getWholeConfig,
|
|
76
|
-
update
|
|
77
|
-
|
|
77
|
+
update({ tag }) {
|
|
78
|
+
return (0, update_1.update)(tag);
|
|
79
|
+
},
|
|
80
|
+
async check_update() {
|
|
81
|
+
return { options: await (0, update_1.getUpdates)() };
|
|
82
|
+
},
|
|
78
83
|
get_custom_html() {
|
|
79
84
|
return {
|
|
80
85
|
sections: Object.fromEntries([
|
|
@@ -101,7 +106,7 @@ exports.adminApis = {
|
|
|
101
106
|
...await (0, listen_1.getServerStatus)(),
|
|
102
107
|
urls: (0, listen_1.getUrls)(),
|
|
103
108
|
baseUrl: middlewares_1.baseUrl.get(),
|
|
104
|
-
|
|
109
|
+
updatePossible: !(0, update_1.updateSupported)() ? false : await (0, update_1.localUpdateAvailable)() ? 'local' : true,
|
|
105
110
|
proxyDetected: (0, middlewares_1.getProxyDetected)(),
|
|
106
111
|
frpDetected: exports.localhostAdmin.get() && !(0, middlewares_1.getProxyDetected)()
|
|
107
112
|
&& (0, connections_1.getConnections)().every(misc_1.isLocalHost)
|
|
@@ -116,10 +121,20 @@ exports.adminApis = {
|
|
|
116
121
|
await (0, promises_1.writeFile)(files.cert, cert);
|
|
117
122
|
return files;
|
|
118
123
|
},
|
|
119
|
-
|
|
124
|
+
get_log({ file = 'log' }, ctx) {
|
|
120
125
|
return new apiMiddleware_1.SendListReadable({
|
|
121
126
|
bufferTime: 10,
|
|
122
|
-
doAtStart(list) {
|
|
127
|
+
async doAtStart(list) {
|
|
128
|
+
if (file === 'console') {
|
|
129
|
+
for (const chunk of lodash_1.default.chunk(consoleLog_1.consoleLog, 1000)) { // avoid occupying the thread too long
|
|
130
|
+
for (const x of chunk)
|
|
131
|
+
list.add(x);
|
|
132
|
+
await (0, misc_1.wait)(0);
|
|
133
|
+
}
|
|
134
|
+
list.ready();
|
|
135
|
+
events_1.default.on('console', x => list.add(x));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
123
138
|
const logger = log_1.loggers.find(l => l.name === file);
|
|
124
139
|
if (!logger)
|
|
125
140
|
return list.error(const_1.HTTP_NOT_FOUND, true);
|
package/src/api.auth.js
CHANGED
|
@@ -7,7 +7,6 @@ const crypt_1 = require("./crypt");
|
|
|
7
7
|
const apiMiddleware_1 = require("./apiMiddleware");
|
|
8
8
|
const tssrp6a_1 = require("tssrp6a");
|
|
9
9
|
const const_1 = require("./const");
|
|
10
|
-
const misc_1 = require("./misc");
|
|
11
10
|
const api_helpers_1 = require("./api.helpers");
|
|
12
11
|
const adminApis_1 = require("./adminApis");
|
|
13
12
|
const middlewares_1 = require("./middlewares");
|
|
@@ -22,12 +21,10 @@ async function loggedIn(ctx, username) {
|
|
|
22
21
|
return ctx.throw(const_1.HTTP_SERVER_ERROR, 'session');
|
|
23
22
|
if (username === false) {
|
|
24
23
|
delete s.username;
|
|
25
|
-
ctx.cookies.set('csrf', '');
|
|
26
24
|
return;
|
|
27
25
|
}
|
|
28
26
|
s.username = (0, perm_1.normalizeUsername)(username);
|
|
29
27
|
await (0, middlewares_1.prepareState)(ctx, async () => { }); // updating the state is necessary to send complete session data so that frontend shows admin button
|
|
30
|
-
ctx.cookies.set('csrf', (0, misc_1.randomId)(), { signed: false, httpOnly: false });
|
|
31
28
|
}
|
|
32
29
|
function makeExp() {
|
|
33
30
|
return !keepSessionAlive.get() ? undefined
|
package/src/api.file_list.js
CHANGED
|
@@ -39,7 +39,7 @@ const file_list = async ({ uri, offset, limit, search, c, sse }, ctx) => {
|
|
|
39
39
|
return { ...props, list: await (0, misc_1.asyncGeneratorToArray)(produceEntries()) };
|
|
40
40
|
setTimeout(async () => {
|
|
41
41
|
if (can_upload || can_delete)
|
|
42
|
-
list.
|
|
42
|
+
list.props(props);
|
|
43
43
|
for await (const entry of produceEntries())
|
|
44
44
|
list.add(entry);
|
|
45
45
|
list.close();
|
|
@@ -103,12 +103,13 @@ async function nodeToDirEntry(ctx, node) {
|
|
|
103
103
|
const pr = node.can_read === vfs_1.WHO_NO_ONE && !(folder && filesInsideCould()) ? 'r'
|
|
104
104
|
: !(0, vfs_1.hasPermission)(node, 'can_read', ctx) ? 'R'
|
|
105
105
|
: '';
|
|
106
|
+
const pd = (0, vfs_1.hasPermission)(node, 'can_delete', ctx) ? 'd' : '';
|
|
106
107
|
return {
|
|
107
108
|
n: name + (folder ? '/' : ''),
|
|
108
109
|
c: ctime,
|
|
109
110
|
m: Math.abs(+mtime - +ctime) < 1000 ? undefined : mtime,
|
|
110
111
|
s: folder ? undefined : st.size,
|
|
111
|
-
p: (pr + pl) || undefined
|
|
112
|
+
p: (pr + pl + pd) || undefined
|
|
112
113
|
};
|
|
113
114
|
}
|
|
114
115
|
catch (_a) {
|
package/src/api.monitor.js
CHANGED
|
@@ -26,47 +26,47 @@ const apis = {
|
|
|
26
26
|
return { result: Boolean(c) };
|
|
27
27
|
},
|
|
28
28
|
get_connections({}, ctx) {
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
|
|
29
|
+
const sent = Symbol('sent');
|
|
30
|
+
const list = new apiMiddleware_1.SendListReadable({
|
|
31
|
+
addAtStart: (0, connections_1.getConnections)().map(c => !ignore(c) && (c[sent] = serializeConnection(c))).filter(Boolean),
|
|
32
|
+
onEnd() {
|
|
33
|
+
for (const c of (0, connections_1.getConnections)())
|
|
34
|
+
delete c[sent];
|
|
35
|
+
}
|
|
36
|
+
});
|
|
32
37
|
list.props({ you: ctx.ip });
|
|
33
38
|
return list.events(ctx, {
|
|
34
39
|
connection(conn) {
|
|
35
|
-
|
|
40
|
+
if (ignore(conn))
|
|
41
|
+
return;
|
|
42
|
+
list.add(conn[sent] = serializeConnection(conn));
|
|
36
43
|
},
|
|
37
44
|
connectionClosed(conn) {
|
|
38
|
-
if (
|
|
45
|
+
if (ignore(conn))
|
|
39
46
|
return;
|
|
40
47
|
list.remove(getConnAddress(conn));
|
|
41
|
-
conn[
|
|
48
|
+
delete conn[sent];
|
|
42
49
|
},
|
|
43
50
|
connectionUpdated(conn, change) {
|
|
44
|
-
if (
|
|
45
|
-
return
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
if (ignore(conn) || ignore(change) || !conn[sent])
|
|
52
|
+
return;
|
|
53
|
+
if (change.ctx) {
|
|
54
|
+
Object.assign(change, fromCtx(change.ctx));
|
|
55
|
+
change.ctx = undefined;
|
|
56
|
+
}
|
|
57
|
+
if (change.opProgress)
|
|
58
|
+
change.opProgress = lodash_1.default.round(change.opProgress, 3);
|
|
59
|
+
// avoid sending non-changes
|
|
60
|
+
const last = conn[sent];
|
|
61
|
+
for (const [k, v] of (0, misc_1.typedEntries)(change))
|
|
62
|
+
if (v === last[k])
|
|
63
|
+
delete change[k];
|
|
64
|
+
if (lodash_1.default.isEmpty(change))
|
|
65
|
+
return;
|
|
66
|
+
Object.assign(last, change);
|
|
67
|
+
list.update(getConnAddress(conn), change);
|
|
50
68
|
},
|
|
51
69
|
});
|
|
52
|
-
function add(conn) {
|
|
53
|
-
if (!cancel(conn))
|
|
54
|
-
return;
|
|
55
|
-
list.add(serializeConnection(conn));
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
function cancel(conn) {
|
|
59
|
-
if (!conn[state])
|
|
60
|
-
return;
|
|
61
|
-
clearTimeout(conn[state]);
|
|
62
|
-
conn[state] = undefined;
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
function update(conn, change) {
|
|
66
|
-
if (conn[state] === false)
|
|
67
|
-
return;
|
|
68
|
-
list.update(getConnAddress(conn), change);
|
|
69
|
-
}
|
|
70
70
|
function serializeConnection(conn) {
|
|
71
71
|
var _a;
|
|
72
72
|
const { socket, started, secure } = conn;
|
|
@@ -87,8 +87,8 @@ const apis = {
|
|
|
87
87
|
agent: getBrowser(ctx.get('user-agent')),
|
|
88
88
|
archive: ctx.state.archive,
|
|
89
89
|
upload: ctx.state.uploadProgress,
|
|
90
|
-
path: ctx.state.uploadPath
|
|
91
|
-
|| (ctx.fileSource || ctx.state.archive) && ctx.path // only uploads and downloads
|
|
90
|
+
path: ctx.state.uploadPath && decodeURIComponent(ctx.state.uploadPath)
|
|
91
|
+
|| (ctx.fileSource || ctx.state.archive) && decodeURIComponent(ctx.path) // only uploads and downloads
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
94
|
},
|
|
@@ -99,13 +99,16 @@ const apis = {
|
|
|
99
99
|
inSpeed: throttler_1.totalInSpeed,
|
|
100
100
|
got: throttler_1.totalGot,
|
|
101
101
|
sent: throttler_1.totalSent,
|
|
102
|
-
connections: (0, connections_1.getConnections)()
|
|
102
|
+
connections: lodash_1.default.sumBy((0, connections_1.getConnections)(), x => ignore(x) ? 0 : 1),
|
|
103
103
|
};
|
|
104
104
|
await (0, misc_1.wait)(1000);
|
|
105
105
|
}
|
|
106
106
|
},
|
|
107
107
|
};
|
|
108
108
|
exports.default = apis;
|
|
109
|
+
function ignore(conn) {
|
|
110
|
+
return false; //conn.socket && isLocalHost(conn)
|
|
111
|
+
}
|
|
109
112
|
function getConnAddress(conn) {
|
|
110
113
|
return {
|
|
111
114
|
ip: conn.ip,
|
package/src/api.vfs.js
CHANGED
|
@@ -78,7 +78,7 @@ const apis = {
|
|
|
78
78
|
const n = await urlToNodeOriginal(uri);
|
|
79
79
|
if (!n)
|
|
80
80
|
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND, 'path not found');
|
|
81
|
-
props = pickProps(props, ['name', 'source', 'masks', 'default', 'accept',
|
|
81
|
+
props = pickProps(props, ['name', 'source', 'masks', 'default', 'accept', ...vfs_1.PERM_KEYS]); // sanitize
|
|
82
82
|
if (props.name && props.name !== (0, vfs_1.getNodeName)(n)) {
|
|
83
83
|
const parent = await urlToNodeOriginal((0, path_1.dirname)(uri));
|
|
84
84
|
if ((_a = parent === null || parent === void 0 ? void 0 : parent.children) === null || _a === void 0 ? void 0 : _a.find(x => (0, vfs_1.getNodeName)(x) === props.name))
|
|
@@ -151,44 +151,47 @@ const apis = {
|
|
|
151
151
|
path = (0, path_1.dirname)(path);
|
|
152
152
|
return { path };
|
|
153
153
|
},
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
try {
|
|
166
|
-
const matching = (0, misc_1.makeMatcher)(fileMask);
|
|
167
|
-
path = (0, misc_1.isWindowsDrive)(path) ? path + '\\' : (0, path_1.resolve)(path || '/');
|
|
168
|
-
for await (const [name, isDir] of (0, misc_1.dirStream)(path)) {
|
|
169
|
-
if (ctx.req.aborted)
|
|
154
|
+
ls({ path, files = true, fileMask }, ctx) {
|
|
155
|
+
return new apiMiddleware_1.SendListReadable({
|
|
156
|
+
async doAtStart(list) {
|
|
157
|
+
if (!path && const_1.IS_WINDOWS) {
|
|
158
|
+
try {
|
|
159
|
+
for (const n of await (0, util_os_1.getDrives)())
|
|
160
|
+
list.add({ n, k: 'd' });
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
console.debug(error);
|
|
164
|
+
}
|
|
170
165
|
return;
|
|
166
|
+
}
|
|
171
167
|
try {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
168
|
+
const matching = (0, misc_1.makeMatcher)(fileMask);
|
|
169
|
+
path = (0, misc_1.isWindowsDrive)(path) ? path + '\\' : (0, path_1.resolve)(path || '/');
|
|
170
|
+
for await (const [name, isDir] of (0, misc_1.dirStream)(path)) {
|
|
171
|
+
if (ctx.req.aborted)
|
|
172
|
+
return;
|
|
173
|
+
if (!isDir)
|
|
174
|
+
if (!files || fileMask && !matching(name))
|
|
175
|
+
continue;
|
|
176
|
+
try {
|
|
177
|
+
const stats = await (0, promises_1.stat)((0, path_1.join)(path, name));
|
|
178
|
+
list.add({
|
|
179
|
+
n: name,
|
|
180
|
+
s: stats.size,
|
|
181
|
+
c: stats.ctime,
|
|
182
|
+
m: stats.mtime,
|
|
183
|
+
k: isDir ? 'd' : undefined,
|
|
184
|
+
});
|
|
183
185
|
}
|
|
184
|
-
|
|
186
|
+
catch (_a) { } // just ignore entries we can't stat
|
|
187
|
+
}
|
|
188
|
+
list.close();
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
list.error(e.code || e.message || String(e), true);
|
|
185
192
|
}
|
|
186
|
-
catch (_a) { } // just ignore entries we can't stat
|
|
187
193
|
}
|
|
188
|
-
}
|
|
189
|
-
catch (e) {
|
|
190
|
-
yield { error: e.code || e.message || String(e) };
|
|
191
|
-
}
|
|
194
|
+
});
|
|
192
195
|
}
|
|
193
196
|
};
|
|
194
197
|
exports.default = apis;
|
package/src/apiMiddleware.js
CHANGED
|
@@ -35,11 +35,18 @@ function apiMiddleware(apis) {
|
|
|
35
35
|
// we don't rely on SameSite cookie option because it's https-only
|
|
36
36
|
let res;
|
|
37
37
|
try {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
if (ctx.state.revProxyPath)
|
|
39
|
+
for (const [k, v] of Object.entries(params))
|
|
40
|
+
if (k.startsWith('uri'))
|
|
41
|
+
if (typeof v === 'string')
|
|
42
|
+
fixUri(params, k);
|
|
43
|
+
else if (typeof (v === null || v === void 0 ? void 0 : v[0]) === 'string')
|
|
44
|
+
v.forEach((x, i) => fixUri(v, i));
|
|
41
45
|
res = csrf && csrf !== params.csrf ? new ApiError(const_1.HTTP_UNAUTHORIZED, 'csrf')
|
|
42
46
|
: await apiFun(params || {}, ctx);
|
|
47
|
+
function fixUri(o, k) {
|
|
48
|
+
o[k] = (0, misc_1.removeStarting)(ctx.state.revProxyPath, o[k]);
|
|
49
|
+
}
|
|
43
50
|
}
|
|
44
51
|
catch (e) {
|
|
45
52
|
res = e;
|
|
@@ -69,18 +76,20 @@ function isAsyncGenerator(x) {
|
|
|
69
76
|
return typeof (x === null || x === void 0 ? void 0 : x.next) === 'function';
|
|
70
77
|
}
|
|
71
78
|
class SendListReadable extends stream_1.Readable {
|
|
72
|
-
constructor({ addAtStart, doAtStart, bufferTime } = {}) {
|
|
79
|
+
constructor({ addAtStart, doAtStart, bufferTime, onEnd } = {}) {
|
|
73
80
|
super({ objectMode: true, read() { } });
|
|
74
81
|
this.buffer = [];
|
|
75
82
|
if (!bufferTime)
|
|
76
|
-
bufferTime =
|
|
83
|
+
bufferTime = 200;
|
|
77
84
|
this.processBuffer = lodash_1.default.debounce(() => {
|
|
78
85
|
this.push(this.buffer);
|
|
79
86
|
this.buffer = [];
|
|
80
87
|
}, bufferTime, { maxWait: bufferTime });
|
|
81
|
-
this.on('end', () =>
|
|
82
|
-
|
|
83
|
-
|
|
88
|
+
this.on('end', () => {
|
|
89
|
+
onEnd === null || onEnd === void 0 ? void 0 : onEnd(this);
|
|
90
|
+
this.destroy();
|
|
91
|
+
});
|
|
92
|
+
setTimeout(() => doAtStart === null || doAtStart === void 0 ? void 0 : doAtStart(this)); // work later, when list object has been received by Koa
|
|
84
93
|
if (addAtStart) {
|
|
85
94
|
for (const x of addAtStart)
|
|
86
95
|
this.add(x);
|
|
@@ -95,25 +104,45 @@ class SendListReadable extends stream_1.Readable {
|
|
|
95
104
|
this.processBuffer();
|
|
96
105
|
}
|
|
97
106
|
add(rec) {
|
|
98
|
-
this._push(
|
|
107
|
+
this._push(['add', rec]);
|
|
99
108
|
}
|
|
100
|
-
remove(
|
|
101
|
-
|
|
109
|
+
remove(search) {
|
|
110
|
+
const match = lodash_1.default.matches(search);
|
|
111
|
+
const idx = lodash_1.default.findIndex(this.buffer, x => match(x[1]));
|
|
112
|
+
const found = this.buffer[idx];
|
|
113
|
+
const op = found === null || found === void 0 ? void 0 : found[0];
|
|
114
|
+
if (op === 'remove')
|
|
115
|
+
return;
|
|
116
|
+
if (found) {
|
|
117
|
+
this.buffer.splice(idx, 1);
|
|
118
|
+
if (op === 'add')
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
this._push(['remove', search]);
|
|
102
122
|
}
|
|
103
123
|
update(search, change) {
|
|
104
|
-
|
|
124
|
+
if (lodash_1.default.isEmpty(change))
|
|
125
|
+
return;
|
|
126
|
+
const match = lodash_1.default.matches(search);
|
|
127
|
+
const found = lodash_1.default.find(this.buffer, x => match(x[1]));
|
|
128
|
+
const op = found === null || found === void 0 ? void 0 : found[0];
|
|
129
|
+
if (op === 'remove')
|
|
130
|
+
return;
|
|
131
|
+
if (op === 'add' || op === 'update')
|
|
132
|
+
return Object.assign(found[op === 'add' ? 1 : 2], change);
|
|
133
|
+
return this._push(['update', search, change]);
|
|
105
134
|
}
|
|
106
135
|
ready() {
|
|
107
|
-
this._push('ready');
|
|
136
|
+
this._push(['ready']);
|
|
108
137
|
}
|
|
109
138
|
custom(data) {
|
|
110
139
|
this._push(data);
|
|
111
140
|
}
|
|
112
141
|
props(props) {
|
|
113
|
-
this._push(
|
|
142
|
+
this._push(['props', props]);
|
|
114
143
|
}
|
|
115
144
|
error(msg, close = false, props) {
|
|
116
|
-
this._push(
|
|
145
|
+
this._push(['error', msg, props]);
|
|
117
146
|
this.lastError = msg;
|
|
118
147
|
if (close)
|
|
119
148
|
this.close();
|
package/src/commands.js
CHANGED
|
@@ -111,8 +111,8 @@ const commands = {
|
|
|
111
111
|
'check-update': {
|
|
112
112
|
params: '',
|
|
113
113
|
async cb() {
|
|
114
|
-
const update = await (0, update_1.
|
|
115
|
-
if (update
|
|
114
|
+
const [update] = await (0, update_1.getUpdates)();
|
|
115
|
+
if (!update)
|
|
116
116
|
throw "you already have the latest version: " + const_1.VERSION;
|
|
117
117
|
console.log("new version available", update.name);
|
|
118
118
|
}
|