hfs 0.31.0 → 0.32.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/admin/assets/{index-04ed2a8c.js → index-9a29f12d.js} +118 -118
- package/{frontend/assets/sha512-2e5489ef.js → admin/assets/sha512-f75a38b7.js} +1 -1
- package/admin/index.html +1 -1
- package/frontend/assets/index-5318f55f.css +1 -0
- package/frontend/assets/index-f7c62045.js +85 -0
- package/{admin/assets/sha512-290a2e16.js → frontend/assets/sha512-0dc3c526.js} +1 -1
- package/frontend/index.html +2 -2
- package/package.json +1 -1
- package/src/api.vfs.js +23 -4
- package/src/apiMiddleware.js +9 -3
- package/src/const.js +1 -1
- package/src/frontEndApis.js +23 -1
- package/src/middlewares.js +4 -3
- package/src/util-files.js +5 -1
- package/frontend/assets/index-9e0ff5b6.css +0 -1
- package/frontend/assets/index-b9a3853c.js +0 -85
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as SF}from"./index-
|
|
1
|
+
import{c as SF}from"./index-f7c62045.js";function OF(iF,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 iF)){const lF=Object.getOwnPropertyDescriptor(tF,w);lF&&Object.defineProperty(iF,w,lF.get?lF:{enumerable:!0,get:()=>tF[w]})}}}return Object.freeze(Object.defineProperty(iF,Symbol.toStringTag,{value:"Module"}))}var EF={},UF={get exports(){return EF},set exports(iF){EF=iF}};/*
|
|
2
2
|
* [js-sha512]{@link https://github.com/emn178/js-sha512}
|
|
3
3
|
*
|
|
4
4
|
* @version 0.8.0
|
package/frontend/index.html
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
<link href="/fontello.css" rel="stylesheet" />
|
|
7
7
|
<script>SESSION = _HFS_SESSION_</script>
|
|
8
8
|
<title>File Server</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
-
<link rel="stylesheet" href="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-f7c62045.js"></script>
|
|
10
|
+
<link rel="stylesheet" href="/assets/index-5318f55f.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
package/package.json
CHANGED
package/src/api.vfs.js
CHANGED
|
@@ -48,6 +48,25 @@ const apis = {
|
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
|
+
async move_vfs({ from, parent }) {
|
|
52
|
+
var _a;
|
|
53
|
+
if (from <= '/' || !parent)
|
|
54
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST);
|
|
55
|
+
const fromNode = await urlToNodeOriginal(from);
|
|
56
|
+
if (!fromNode)
|
|
57
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND, 'from not found');
|
|
58
|
+
const parentNode = await urlToNodeOriginal(parent);
|
|
59
|
+
if (!parentNode)
|
|
60
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND, 'parent not found');
|
|
61
|
+
const name = (0, vfs_1.getNodeName)(fromNode);
|
|
62
|
+
if ((_a = parentNode.children) === null || _a === void 0 ? void 0 : _a.find(x => name === (0, vfs_1.getNodeName)(x)))
|
|
63
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_CONFLICT, 'item with same name already present in destination');
|
|
64
|
+
const oldParent = await urlToNodeOriginal((0, path_1.dirname)(from));
|
|
65
|
+
lodash_1.default.pull(oldParent.children, fromNode);
|
|
66
|
+
(parentNode.children || (parentNode.children = [])).push(fromNode);
|
|
67
|
+
await (0, vfs_1.saveVfs)();
|
|
68
|
+
return {};
|
|
69
|
+
},
|
|
51
70
|
async set_vfs({ uri, props }) {
|
|
52
71
|
const n = await urlToNodeOriginal(uri);
|
|
53
72
|
if (!n)
|
|
@@ -62,12 +81,12 @@ const apis = {
|
|
|
62
81
|
await (0, vfs_1.saveVfs)();
|
|
63
82
|
return n;
|
|
64
83
|
},
|
|
65
|
-
async add_vfs({
|
|
66
|
-
const n =
|
|
84
|
+
async add_vfs({ parent, source, name }) {
|
|
85
|
+
const n = parent ? await urlToNodeOriginal(parent) : vfs_1.vfs;
|
|
67
86
|
if (!n)
|
|
68
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND, 'invalid
|
|
87
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND, 'invalid parent');
|
|
69
88
|
if (n.isTemp || !await (0, vfs_1.nodeIsDirectory)(n))
|
|
70
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_ACCEPTABLE, 'invalid
|
|
89
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_ACCEPTABLE, 'invalid parent');
|
|
71
90
|
if ((0, misc_1.isWindowsDrive)(source))
|
|
72
91
|
source += '\\'; // slash must be included, otherwise it will refer to the cwd of that drive
|
|
73
92
|
const a = n.children || (n.children = []);
|
package/src/apiMiddleware.js
CHANGED
|
@@ -29,8 +29,14 @@ function apiMiddleware(apis) {
|
|
|
29
29
|
}
|
|
30
30
|
const csrf = ctx.cookies.get('csrf');
|
|
31
31
|
// we don't rely on SameSite cookie option because it's https-only
|
|
32
|
-
let res
|
|
33
|
-
|
|
32
|
+
let res;
|
|
33
|
+
try {
|
|
34
|
+
res = csrf && csrf !== ctx.params.csrf ? new ApiError(const_1.HTTP_UNAUTHORIZED, 'csrf')
|
|
35
|
+
: await apiFun(ctx.params || {}, ctx);
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
res = e;
|
|
39
|
+
}
|
|
34
40
|
if (isAsyncGenerator(res))
|
|
35
41
|
res = (0, misc_1.asyncGeneratorToReadable)(res);
|
|
36
42
|
if (res instanceof stream_1.Readable) { // Readable, we'll go SSE-mode
|
|
@@ -45,7 +51,7 @@ function apiMiddleware(apis) {
|
|
|
45
51
|
return ctx.status = res.status;
|
|
46
52
|
}
|
|
47
53
|
if (res instanceof Error) { // generic exception
|
|
48
|
-
ctx.body = String(res);
|
|
54
|
+
ctx.body = res.message || String(res);
|
|
49
55
|
return ctx.status = const_1.HTTP_BAD_REQUEST;
|
|
50
56
|
}
|
|
51
57
|
ctx.body = res;
|
package/src/const.js
CHANGED
|
@@ -38,7 +38,7 @@ 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-02-
|
|
41
|
+
exports.BUILD_TIMESTAMP = "2023-02-13T10:07:32.320Z";
|
|
42
42
|
const pkg = JSON.parse(fs.readFileSync(PKG_PATH, 'utf8'));
|
|
43
43
|
exports.VERSION = pkg.version;
|
|
44
44
|
exports.DAY = 86400000;
|
package/src/frontEndApis.js
CHANGED
|
@@ -33,6 +33,11 @@ const api_file_list_1 = require("./api.file_list");
|
|
|
33
33
|
const api_auth = __importStar(require("./api.auth"));
|
|
34
34
|
const config_1 = require("./config");
|
|
35
35
|
const events_1 = __importDefault(require("./events"));
|
|
36
|
+
const util_files_1 = require("./util-files");
|
|
37
|
+
const const_1 = require("./const");
|
|
38
|
+
const vfs_1 = require("./vfs");
|
|
39
|
+
const promises_1 = require("fs/promises");
|
|
40
|
+
const path_1 = require("path");
|
|
36
41
|
const customHeader = (0, config_1.defineConfig)('custom_header');
|
|
37
42
|
exports.frontEndApis = {
|
|
38
43
|
file_list: api_file_list_1.file_list,
|
|
@@ -48,7 +53,24 @@ exports.frontEndApis = {
|
|
|
48
53
|
list.custom({ name, data });
|
|
49
54
|
}
|
|
50
55
|
});
|
|
51
|
-
}
|
|
56
|
+
},
|
|
57
|
+
async create_folder({ path, name }, ctx) {
|
|
58
|
+
if (!(0, util_files_1.isValidFileName)(name) || (0, util_files_1.dirTraversal)(name))
|
|
59
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST, 'bad name');
|
|
60
|
+
const parentNode = await (0, vfs_1.urlToNode)(path);
|
|
61
|
+
if (!parentNode)
|
|
62
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND, 'parent not found');
|
|
63
|
+
const { source } = parentNode;
|
|
64
|
+
if (!source || !(0, vfs_1.hasPermission)(parentNode, 'can_upload', ctx))
|
|
65
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_FORBIDDEN);
|
|
66
|
+
try {
|
|
67
|
+
await (0, promises_1.mkdir)((0, path_1.join)(source, name));
|
|
68
|
+
return {};
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
return new apiMiddleware_1.ApiError(e.code === 'EEXIST' ? const_1.HTTP_CONFLICT : const_1.HTTP_BAD_REQUEST, e);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
52
74
|
};
|
|
53
75
|
function notifyClient(ctx, name, data) {
|
|
54
76
|
const { notificationChannel } = ctx.query;
|
package/src/middlewares.js
CHANGED
|
@@ -151,14 +151,14 @@ const someSecurity = async (ctx, next) => {
|
|
|
151
151
|
if (const_1.DEV && proxy && [process.env.FRONTEND_PROXY, process.env.ADMIN_PROXY].includes(ctx.get('X-Forwarded-port')))
|
|
152
152
|
proxy = '';
|
|
153
153
|
if ((0, misc_1.dirTraversal)(decodeURI(ctx.path)))
|
|
154
|
-
return ctx.status =
|
|
154
|
+
return ctx.status = const_1.HTTP_FOOL;
|
|
155
155
|
if ((0, block_1.applyBlock)(ctx.socket, ctx.ip))
|
|
156
156
|
return;
|
|
157
157
|
proxyDetected || (proxyDetected = proxy > '');
|
|
158
158
|
ctx.state.proxiedFor = proxy;
|
|
159
159
|
}
|
|
160
160
|
catch (_a) {
|
|
161
|
-
return ctx.status =
|
|
161
|
+
return ctx.status = const_1.HTTP_FOOL;
|
|
162
162
|
}
|
|
163
163
|
return next();
|
|
164
164
|
};
|
|
@@ -196,7 +196,8 @@ async function srpCheck(username, password) {
|
|
|
196
196
|
}
|
|
197
197
|
// unify get/post parameters, with JSON decoding to not be limited to strings
|
|
198
198
|
const paramsDecoder = async (ctx, next) => {
|
|
199
|
-
ctx.params = ctx.method === 'POST'
|
|
199
|
+
ctx.params = ctx.method === 'POST' && ctx.originalUrl.startsWith(const_1.API_URI)
|
|
200
|
+
? (0, misc_1.tryJson)(await (0, misc_1.stream2string)(ctx.req))
|
|
200
201
|
: (0, misc_1.objSameKeys)(ctx.query, x => Array.isArray(x) ? x : (0, misc_1.tryJson)(x));
|
|
201
202
|
await next();
|
|
202
203
|
};
|
package/src/util-files.js
CHANGED
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.prepareFolder = exports.unzip = exports.dirStream = exports.adjustStaticPathForGlob = exports.isWindowsDrive = exports.dirTraversal = exports.watchDir = exports.readFileBusy = exports.isFile = exports.isDirectory = void 0;
|
|
7
|
+
exports.isValidFileName = exports.prepareFolder = exports.unzip = exports.dirStream = exports.adjustStaticPathForGlob = exports.isWindowsDrive = exports.dirTraversal = exports.watchDir = exports.readFileBusy = exports.isFile = exports.isDirectory = void 0;
|
|
8
8
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
9
|
const misc_1 = require("./misc");
|
|
10
10
|
const fs_1 = require("fs");
|
|
@@ -152,3 +152,7 @@ async function prepareFolder(path, dirnameIt = true) {
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
exports.prepareFolder = prepareFolder;
|
|
155
|
+
function isValidFileName(name) {
|
|
156
|
+
return !/^\.\.?$|[/:*?"<>|\\]/.test(name);
|
|
157
|
+
}
|
|
158
|
+
exports.isValidFileName = isValidFileName;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@charset "UTF-8";:root{height:100dvh;--bg: #fff;--text: #555;--ghost-contrast: #8882;--faint-contrast: #8884;--mild-contrast: #8886;--good-contrast: #000a;--button-bg: #68a;--button-text: #fff;--focus-color: #468}:root .theme-dark{--bg: #000;--text: #999;--good-contrast: #fffa;--button-bg: #345;--button-text: #999;color-scheme:dark}:root .theme-dark a{color:#8ac}:root .theme-dark .dialog-closer{background:#633}:root .theme-dark .dialog-icon{color:#ccc}:root .theme-dark .dialog-icon .icon{color:#aaa;margin-left:-1px;font-size:95%}:root .theme-dark .dialog-backdrop{background:rgba(51,51,51,.7333333333)}:root .theme-dark .error-msg{color:#b88;background-color:#623}body{background:var(--bg);margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body,button,select,input{font-size:12pt}#root{max-width:50em;margin:auto;min-height:100vh;display:flex;flex-direction:column}body,input{color:var(--text)}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}input,select{padding:.3em .4em;border-radius:.5em;background:var(--bg);border-color:var(--mild-contrast);color:var(--good-contrast);max-width:100%;box-sizing:border-box}input[type=checkbox]{transform:scale(1.7);accent-color:var(--button-bg)}label input[type=checkbox]{margin-right:.8em}select{text-align:center}.hidden{display:none!important}.icon{font-size:1.2em}.icon.mirror:before{transform:scaleX(-1)}a{text-decoration:none;color:#57a}button{background-color:var(--button-bg);color:var(--button-text);padding:.5em 1em;border:transparent;text-decoration:none;border-radius:.3em;vertical-align:middle;cursor:pointer}button.toggled{filter:brightness(.6)}button:focus-visible,.breadcrumb:focus-visible{outline:3px solid var(--focus-color)}input:focus-visible,select:focus-visible,ul a:focus-visible{border-radius:.3em;border-color:transparent;outline:2px solid var(--focus-color)}.error-msg{background-color:#faa;color:#833;padding:.5em 1em}header{position:sticky;top:0;background:var(--bg);padding:.2em;z-index:1}.ani-working{animation:1s blink infinite}@keyframes blink{0%{opacity:1}50%{opacity:.2}}@keyframes spin{to{transform:rotate(360deg)}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.spinner,.icon.spinner:before{animation:1.5s spin infinite linear}.icon.emoji.spinner{display:inline-block}.breadcrumb{padding:.1em .6em .2em;line-height:1.8em;border-radius:.7em;background-color:var(--button-bg);color:var(--button-text);border-top:1px solid #666;margin-right:-.1em}.breadcrumb:nth-child(-n+3) .icon{padding:0 .2em}#folder-stats{font-size:90%;margin:.4em 0 0 .5em;float:right}#folder-stats .icon{margin-right:.3em}#filter{flex:1;margin:.2em auto;box-sizing:border-box}#filter-bar{display:flex;align-items:center;gap:.3em;margin:.3em 0 .1em;padding-left:11px}#filter-bar input[type=checkbox]{margin-right:.7em}ul.dir{flex:1;padding:0;margin:0;clear:both}ul.dir>p{text-align:center}ul.dir li{display:block;list-style-type:none;padding:.3em .3em .4em;border-bottom:1px solid var(--faint-contrast)}ul.dir li:nth-of-type(odd){background-color:var(--ghost-contrast)}ul.dir li input[type=checkbox]{margin:0 .8em}ul.dir li a{word-break:break-word;padding-right:.3em}ul.dir li a .icon{margin-right:.3em}ul.dir li a.container-folder:hover{text-decoration:underline}ul.dir li .entry-props{float:right;font-size:90%;margin-left:4px;margin-top:.3em;font-variant-numeric:tabular-nums}ul.dir li .entry-props .entry-size-unit{display:inline-block;margin-left:.3em;width:1.5em}ul.dir li.page-separator{margin-top:1em;position:relative}ul.dir li.page-separator:before{content:attr(label);position:absolute;top:-1.5em;width:50%;padding-left:50%;background:var(--bg);background:linear-gradient(0deg,var(--bg) 40%,var(--button-bg) 50%,var(--bg) 60%);font-size:smaller;margin-left:-.3em;filter:brightness(.7);text-shadow:0 0 6px var(--bg)}#menu-panel{margin-bottom:.2em}#menu-bar{display:flex;justify-content:space-evenly;flex-wrap:wrap}#menu-bar>*{flex:auto;margin:.1em}#menu-bar button{padding-left:0;padding-right:0}#menu-bar>a>button{width:100%}#searched{margin:.2em}#user-panel{display:flex;flex-direction:column;gap:1em}#user-panel a>button{width:100%}button label{cursor:inherit;margin-left:.5em}.dialog-backdrop.working{font-size:5em;animation:1s fade-in}.dialog-content{padding:.2em}.dialog{min-width:10em;--color: var(--button-bg)}#paging{position:sticky;bottom:0;display:flex;gap:.2em;background:var(--bg);padding:0 .2em .2em}#paging,#paging>button{box-shadow:0 0 .3em .3em var(--bg);z-index:1}#paging #paging-middle{display:flex;gap:.5em;flex:1;overflow-x:auto}#paging *::-webkit-scrollbar{height:8px}#paging #paging-middle>button{flex:1;padding-top:0;padding-bottom:0}#paging button{min-width:2.5em;background:var(--button-bg);text-align:center;white-space:nowrap;padding:.5em}.upload-progress:before{content:" \2013 "}.upload-progress{min-width:4em;display:inline-block;margin-left:.5em}.upload-list td:nth-child(1){width:0}.upload-list td:nth-child(2){text-align:right;width:0;white-space:nowrap;padding-left:.5em}.upload-list td:nth-child(3){padding:.2em .5em;word-break:break-word}.dialog-login form{display:flex;flex-direction:column;gap:1.2em}.dialog-login label{display:block;margin-bottom:.5em;margin-left:.1em}*{scrollbar-width:thin;scrollbar-color:var(--button-bg) var(--ghost-contrast)}*::-webkit-scrollbar{width:12px}*::-webkit-scrollbar-track{background:var(--ghost-contrast)}*::-webkit-scrollbar-thumb{background-color:var(--button-bg);border-radius:20px;border:1px solid var(--ghost-contrast)}@media (max-width: 42em){:root{--ghost-contrast: #8883}body,button,select{font-size:14pt}#menu-bar button label,#filter-bar button label{display:none}#filter-bar{margin:.2em 0}#filter-bar button{width:17.6vw;height:2.3em}.breadcrumb{word-break:break-all}.breadcrumb .icon{font-size:24px}}.dialog-backdrop{position:fixed;inset:0;background:#888a;display:flex;justify-content:center;align-items:center;z-index:1000}.dialog{background:#fff;background:var(--bg);padding:max(.5em,1vw);border-radius:1em;position:relative;margin:0 3vw;overflow:hidden;max-height:calc(100vh - 2em)}.dialog-icon{color:#fff;background-color:var(--color);position:absolute;top:0;width:1.8em;height:1.7em;text-align:center;border-radius:.8em 0}.dialog-title{margin-top:-.4em;font-size:110%}.dialog-icon~.dialog-title{text-align:center}.dialog-closer{border-radius:0 .8em;right:0;padding:0;background-color:#c88}.dialog-icon~.dialog-content{margin-top:2em}.dialog-type{left:0;top:0;overflow:hidden;line-height:1.7em;opacity:.8}.dialog-content{overflow:auto;max-height:calc(100vh - 4.5em)}.dialog-content p{white-space:pre-wrap;margin:.5em 0}.dialog-confirm .dialog-content button{margin-top:1em}.dialog-alert-info{--color: #282 }.dialog-alert-warning{--color: #c91 }.dialog-alert-error{--color: #822}@media (max-width: 50em){.dialog-closer{font-size:120%}.dialog-icon~.dialog-content{margin-top:2em}}.dialog-prompt label{display:block;margin-bottom:.5em;margin-left:.1em}
|