hfs 0.33.0 → 0.34.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.
@@ -1,4 +1,4 @@
1
- import{c as SF}from"./index-5e32462d.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}};/*
1
+ import{c as SF}from"./index-f36b3979.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
@@ -4,10 +4,11 @@
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
+ <link rel="icon"/>
7
8
  <script>SESSION = _HFS_SESSION_</script>
8
9
  <title>File Server</title>
9
- <script type="module" crossorigin src="/assets/index-71b9ad8e.js"></script>
10
- <link rel="stylesheet" href="/assets/index-a6f88231.css">
10
+ <script type="module" crossorigin src="/assets/index-f36b3979.js"></script>
11
+ <link rel="stylesheet" href="/assets/index-eebe42f5.css">
11
12
  </head>
12
13
  <body>
13
14
  <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.33.0",
3
+ "version": "0.34.0",
4
4
  "description": "HTTP File Server",
5
5
  "keywords": [
6
6
  "file server",
@@ -1,5 +1,5 @@
1
1
  exports.description = "Counts downloads for each file, and displays the total in the list"
2
- exports.version = 2 // comply to new async init/unload
2
+ exports.version = 3 // stylizable
3
3
  exports.apiRequired = 3
4
4
 
5
5
  exports.init = async api => {
@@ -28,7 +28,8 @@ exports.init = async api => {
28
28
  }
29
29
 
30
30
  return {
31
- frontend_js: 'hits.js',
31
+ frontend_js: 'main.js',
32
+ frontend_css: 'style.css',
32
33
  unload: () => save.flush(), // we may have pending savings
33
34
  middleware: (ctx) =>
34
35
  () => { // execute after other middlewares are done
@@ -0,0 +1,2 @@
1
+ HFS.onEvent('additionalEntryProps', ({ entry: { hits } }) =>
2
+ hits && '<span class="download-counter">' + hits + '</span>')
@@ -0,0 +1,2 @@
1
+ .download-counter::before { content: "Hits: " }
2
+ .download-counter::after { content: " — " }
@@ -31,14 +31,15 @@ const file_list = async ({ path, offset, limit, search, omit, sse }, ctx) => {
31
31
  const walker = (0, vfs_1.walkNode)(node, ctx, search ? Infinity : 0);
32
32
  const onDirEntryHandlers = (0, plugins_1.mapPlugins)(plug => plug.onDirEntry);
33
33
  const can_upload = (0, vfs_1.hasPermission)(node, 'can_upload', ctx);
34
+ const can_delete = (0, vfs_1.hasPermission)(node, 'can_delete', ctx);
34
35
  if (!sse)
35
36
  return {
36
- can_upload,
37
+ can_upload, can_delete,
37
38
  list: await (0, misc_1.asyncGeneratorToArray)(produceEntries())
38
39
  };
39
40
  setTimeout(async () => {
40
- if (can_upload)
41
- list.custom({ props: { can_upload } });
41
+ if (can_upload || can_delete)
42
+ list.custom({ props: { can_upload, can_delete } });
42
43
  for await (const entry of produceEntries())
43
44
  list.add(entry);
44
45
  list.close();
package/src/api.vfs.js CHANGED
@@ -25,25 +25,20 @@ const apis = {
25
25
  defaultPerms: vfs_1.defaultPerms,
26
26
  };
27
27
  async function recur(node) {
28
- const dir = await (0, vfs_1.nodeIsDirectory)(node);
29
- const stats = {};
30
- try {
31
- if (!dir)
32
- Object.assign(stats, lodash_1.default.pick(await (0, promises_1.stat)(node.source), ['size', 'ctime', 'mtime']));
33
- }
34
- catch (_a) {
35
- stats.size = -1;
36
- }
37
- if (stats && Number(stats.mtime) === Number(stats.ctime))
38
- delete stats.mtime;
28
+ const stats = Boolean(node.source) && await (0, promises_1.stat)(node.source).catch(e => false);
29
+ const isDir = !node.source || stats && stats.isDirectory();
30
+ const copyStats = stats ? lodash_1.default.pick(stats, ['size', 'ctime', 'mtime'])
31
+ : { size: node.source ? -1 : undefined };
32
+ if (copyStats.mtime && Number(copyStats.mtime) === Number(copyStats.ctime))
33
+ delete copyStats.mtime;
39
34
  const isRoot = node === vfs_1.vfs;
40
35
  return {
41
- ...stats,
36
+ ...copyStats,
42
37
  ...node,
43
- website: dir && node.source && await (0, promises_1.stat)((0, path_1.join)(node.source, 'index.html')).then(() => true, () => undefined)
38
+ website: isDir && node.source && await (0, promises_1.stat)((0, path_1.join)(node.source, 'index.html')).then(() => true, () => undefined)
44
39
  || undefined,
45
40
  name: isRoot ? undefined : (0, vfs_1.getNodeName)(node),
46
- type: dir ? 'folder' : undefined,
41
+ type: isDir ? 'folder' : undefined,
47
42
  children: node.children && await Promise.all(node.children.map(recur)),
48
43
  };
49
44
  }
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-14T16:35:07.069Z";
41
+ exports.BUILD_TIMESTAMP = "2023-02-15T23:42:05.075Z";
42
42
  const pkg = JSON.parse(fs.readFileSync(PKG_PATH, 'utf8'));
43
43
  exports.VERSION = pkg.version;
44
44
  exports.DAY = 86400000;
@@ -46,6 +46,7 @@ exports.frontEndApis = {
46
46
  return Object.fromEntries([customHeader].map(x => [x.key(), x.get()]));
47
47
  },
48
48
  get_notifications({ channel }, ctx) {
49
+ apiAssertTypes({ string: { channel } });
49
50
  const list = new apiMiddleware_1.SendListReadable();
50
51
  list.ready(); // on chrome109 EventSource doesn't emit 'open' until something is sent
51
52
  return list.events(ctx, {
@@ -55,9 +56,10 @@ exports.frontEndApis = {
55
56
  });
56
57
  },
57
58
  async create_folder({ path, name }, ctx) {
59
+ apiAssertTypes({ string: { path, name } });
58
60
  if (!(0, util_files_1.isValidFileName)(name) || (0, util_files_1.dirTraversal)(name))
59
61
  return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST, 'bad name');
60
- const parentNode = await (0, vfs_1.urlToNode)(path);
62
+ const parentNode = await (0, vfs_1.urlToNode)(path, ctx);
61
63
  if (!parentNode)
62
64
  return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND, 'parent not found');
63
65
  const { source } = parentNode;
@@ -71,6 +73,23 @@ exports.frontEndApis = {
71
73
  return new apiMiddleware_1.ApiError(e.code === 'EEXIST' ? const_1.HTTP_CONFLICT : const_1.HTTP_BAD_REQUEST, e);
72
74
  }
73
75
  },
76
+ async del({ path }, ctx) {
77
+ apiAssertTypes({ string: { path } });
78
+ const node = await (0, vfs_1.urlToNode)(path, ctx);
79
+ if (!node)
80
+ throw new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
81
+ if (!node.source)
82
+ throw new apiMiddleware_1.ApiError(const_1.HTTP_FORBIDDEN);
83
+ if (!(0, vfs_1.hasPermission)(node, 'can_delete', ctx))
84
+ throw new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED);
85
+ try {
86
+ await (0, promises_1.rm)(node.source, { recursive: true });
87
+ return {};
88
+ }
89
+ catch (e) {
90
+ throw new apiMiddleware_1.ApiError(e.code || const_1.HTTP_SERVER_ERROR, e);
91
+ }
92
+ },
74
93
  };
75
94
  function notifyClient(ctx, name, data) {
76
95
  const { notificationChannel } = ctx.query;
@@ -79,3 +98,9 @@ function notifyClient(ctx, name, data) {
79
98
  }
80
99
  exports.notifyClient = notifyClient;
81
100
  const NOTIFICATION_PREFIX = 'notificationChannel:';
101
+ function apiAssertTypes(paramsByType) {
102
+ for (const [type, params] of Object.entries(paramsByType))
103
+ for (const [name, val] of Object.entries(params))
104
+ if (typeof val !== type)
105
+ throw new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST, 'bad ' + name);
106
+ }
package/src/serveFile.js CHANGED
@@ -68,7 +68,7 @@ function serveFile(source, mime, content) {
68
68
  const range = getRange(ctx, stats.size);
69
69
  ctx.body = (0, fs_1.createReadStream)(source, range);
70
70
  }
71
- catch (_a) {
71
+ catch (e) {
72
72
  return ctx.status = const_1.HTTP_NOT_FOUND;
73
73
  }
74
74
  };
@@ -36,6 +36,7 @@ const api_auth_1 = require("./api.auth");
36
36
  const apiMiddleware_1 = require("./apiMiddleware");
37
37
  const path_1 = require("path");
38
38
  const misc_1 = require("./misc");
39
+ const adminApis_1 = require("./adminApis");
39
40
  // in case of dev env we have our static files within the 'dist' folder'
40
41
  const DEV_STATIC = process.env.DEV ? 'dist/' : '';
41
42
  function serveStatic(uri) {
@@ -80,6 +81,7 @@ async function treatIndex(ctx, body, filesUri) {
80
81
  ctx.set('etag', '');
81
82
  return body
82
83
  .replace(/((?:src|href) *= *['"])\/?(?![a-z]+:\/\/)/g, '$1' + filesUri)
84
+ .replace('<link rel="icon"/>', `<link rel="icon" href="${adminApis_1.favicon.get() ? '/favicon.ico' : 'data;'}" />`)
83
85
  .replace('_HFS_SESSION_', session instanceof apiMiddleware_1.ApiError ? 'null' : JSON.stringify(session))
84
86
  // replacing this text allow us to avoid injecting in frontends that don't support plugins. Don't use a <--comment--> or it will be removed by webpack
85
87
  .replace('_HFS_PLUGINS_', pluginsInjection);
package/src/vfs.js CHANGED
@@ -22,6 +22,7 @@ exports.defaultPerms = {
22
22
  can_see: WHO_ANYONE,
23
23
  can_read: WHO_ANYONE,
24
24
  can_upload: WHO_NO_ONE,
25
+ can_delete: WHO_NO_ONE,
25
26
  };
26
27
  exports.MIME_AUTO = 'auto';
27
28
  function inheritFromParent(parent, child) {