hfs 0.26.9 → 0.27.2

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.
Files changed (54) hide show
  1. package/README.md +15 -2
  2. package/admin/assets/index-509bb1d6.js +415 -0
  3. package/admin/assets/index-60a380a7.css +1 -0
  4. package/{frontend/assets/sha512.6af42937.js → admin/assets/sha512-738f0943.js} +2 -2
  5. package/admin/index.html +2 -2
  6. package/frontend/assets/index-6e178dfd.css +1 -0
  7. package/frontend/assets/index-aea7654e.js +85 -0
  8. package/{admin/assets/sha512.9dfe82e1.js → frontend/assets/sha512-bf915587.js} +2 -2
  9. package/frontend/index.html +3 -3
  10. package/package.json +2 -6
  11. package/plugins/vhosting/plugin.js +23 -20
  12. package/src/QuickZipStream.js +1 -1
  13. package/src/ThrottledStream.js +1 -1
  14. package/src/adminApis.js +5 -5
  15. package/src/api.accounts.js +10 -10
  16. package/src/api.auth.js +17 -17
  17. package/src/api.file_list.js +13 -6
  18. package/src/api.helpers.js +6 -6
  19. package/src/api.monitor.js +2 -0
  20. package/src/api.plugins.js +1 -0
  21. package/src/api.vfs.js +15 -12
  22. package/src/apiMiddleware.js +7 -4
  23. package/src/block.js +1 -0
  24. package/src/commands.js +1 -0
  25. package/src/config.js +1 -1
  26. package/src/connections.js +1 -1
  27. package/src/const.js +18 -7
  28. package/src/crypt.js +1 -1
  29. package/src/debounceAsync.js +1 -0
  30. package/src/events.js +1 -1
  31. package/src/frontEndApis.js +1 -1
  32. package/src/github.js +3 -1
  33. package/src/index.js +3 -2
  34. package/src/listen.js +1 -1
  35. package/src/log.js +4 -4
  36. package/src/middlewares.js +30 -10
  37. package/src/misc.js +1 -1
  38. package/src/perm.js +31 -29
  39. package/src/plugins.js +1 -1
  40. package/src/serveFile.js +11 -11
  41. package/src/serveGuiFiles.js +4 -4
  42. package/src/sse.js +3 -2
  43. package/src/throttler.js +1 -1
  44. package/src/update.js +1 -0
  45. package/src/util-files.js +17 -2
  46. package/src/util-generators.js +1 -0
  47. package/src/util-http.js +3 -1
  48. package/src/vfs.js +29 -27
  49. package/src/watchLoad.js +1 -1
  50. package/src/zip.js +3 -2
  51. package/admin/assets/index.bb5198ec.js +0 -281
  52. package/admin/assets/index.dcc78777.css +0 -1
  53. package/frontend/assets/index.27a78796.js +0 -85
  54. package/frontend/assets/index.93366732.css +0 -1
package/src/util-files.js CHANGED
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
+ // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
5
  };
5
6
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.unzip = exports.run = exports.dirStream = exports.adjustStaticPathForGlob = exports.isWindowsDrive = exports.dirTraversal = exports.watchDir = exports.readFileBusy = exports.isFile = exports.isDirectory = void 0;
7
+ exports.prepareFolder = exports.unzip = exports.run = exports.dirStream = exports.adjustStaticPathForGlob = exports.isWindowsDrive = exports.dirTraversal = exports.watchDir = exports.readFileBusy = exports.isFile = exports.isDirectory = void 0;
7
8
  const promises_1 = __importDefault(require("fs/promises"));
8
9
  const misc_1 = require("./misc");
9
10
  const fs_1 = require("fs");
@@ -140,9 +141,23 @@ async function unzip(stream, cb) {
140
141
  return entry.autodrain();
141
142
  await pending; // don't overlap writings
142
143
  console.debug('unzip', dest);
143
- (0, fs_1.mkdirSync)((0, path_1.dirname)(dest), { recursive: true }); // easy way be sure to have the folder ready before proceeding
144
+ await prepareFolder(dest);
144
145
  const thisFile = entry.pipe((0, fs_1.createWriteStream)(dest));
145
146
  pending = (0, stream_1.once)(thisFile, 'finish');
146
147
  }));
147
148
  }
148
149
  exports.unzip = unzip;
150
+ async function prepareFolder(path, dirnameIt = true) {
151
+ if (dirnameIt)
152
+ path = (0, path_1.dirname)(path);
153
+ if (isWindowsDrive(path))
154
+ return;
155
+ try {
156
+ await promises_1.default.mkdir(path, { recursive: true });
157
+ return true;
158
+ }
159
+ catch (_a) {
160
+ return false;
161
+ }
162
+ }
163
+ exports.prepareFolder = prepareFolder;
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.asyncGeneratorToReadable = exports.asyncGeneratorToArray = exports.filterMapGenerator = void 0;
4
5
  // callback can return undefined to skip element
package/src/util-http.js CHANGED
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
+ // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
5
  };
5
6
  Object.defineProperty(exports, "__esModule", { value: true });
6
7
  exports.httpsStream = exports.httpsString = void 0;
7
8
  const node_https_1 = __importDefault(require("node:https"));
9
+ const const_1 = require("./const");
8
10
  function httpsString(url, options = {}) {
9
11
  return httpsStream(url, options).then(res => new Promise(resolve => {
10
12
  let buf = '';
@@ -21,7 +23,7 @@ function httpsStream(url, options = {}) {
21
23
  node_https_1.default.request(url, options, res => {
22
24
  if (!res.statusCode || res.statusCode >= 400)
23
25
  throw res;
24
- if (res.statusCode === 302 && res.headers.location)
26
+ if (res.statusCode === const_1.HTTP_TEMPORARY_REDIRECT && res.headers.location)
25
27
  return resolve(httpsStream(res.headers.location, options));
26
28
  resolve(res);
27
29
  }).on('error', reject).end();
package/src/vfs.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
+ // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
3
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
@@ -21,6 +21,7 @@ const WHO_ANY_ACCOUNT = '*';
21
21
  exports.defaultPerms = {
22
22
  can_see: WHO_ANYONE,
23
23
  can_read: WHO_ANYONE,
24
+ can_upload: WHO_NO_ONE,
24
25
  };
25
26
  exports.MIME_AUTO = 'auto';
26
27
  function inheritFromParent(parent, child) {
@@ -36,7 +37,7 @@ function inheritFromParent(parent, child) {
36
37
  child.mime || (child.mime = parent.mime);
37
38
  return child;
38
39
  }
39
- async function urlToNode(url, ctx, parent = exports.vfs) {
40
+ async function urlToNode(url, ctx, parent = exports.vfs, getRest) {
40
41
  var _a;
41
42
  let initialSlashes = 0;
42
43
  while (url[initialSlashes] === '/')
@@ -48,25 +49,23 @@ async function urlToNode(url, ctx, parent = exports.vfs) {
48
49
  const rest = nextSlash < 0 ? '' : url.slice(nextSlash + 1, url.endsWith('/') ? -1 : undefined);
49
50
  if ((0, misc_1.dirTraversal)(name) || /[\/]/.test(name)) {
50
51
  if (ctx)
51
- ctx.status = 418;
52
+ ctx.status = const_1.HTTP_FOOL;
52
53
  return;
53
54
  }
54
- const parents = parent.parents || []; // don't waste time cloning the array, as we won't keep intermediate nodes
55
+ // does the tree node have a child that goes by this name?
56
+ const sameName = !const_1.IS_WINDOWS ? (x) => x === name // easy
57
+ : (0, misc_2.with_)(name.toLowerCase(), lc => (x) => x.toLowerCase() === lc);
58
+ const child = (_a = parent.children) === null || _a === void 0 ? void 0 : _a.find(x => sameName(getNodeName(x)));
55
59
  const ret = {
60
+ ...child,
61
+ original: child,
56
62
  isTemp: true,
57
- url: (0, misc_1.enforceFinal)('/', parent.url || '') + name,
58
- parents,
59
63
  };
60
- parents.push(parent);
61
64
  inheritFromParent(parent, ret);
62
65
  inheritMasks(ret, parent, name);
63
66
  applyMasks(ret, parent, name);
64
- // does the tree node have a child that goes by this name?
65
- const sameName = !const_1.IS_WINDOWS ? (x) => x === name // easy
66
- : (0, misc_2.with_)(name.toLowerCase(), lc => (x) => x.toLowerCase() === lc);
67
- const child = (_a = parent.children) === null || _a === void 0 ? void 0 : _a.find(x => sameName(getNodeName(x)));
68
67
  if (child) // yes
69
- return urlToNode(rest, ctx, Object.assign(ret, child, { original: child }));
68
+ return urlToNode(rest, ctx, ret, getRest);
70
69
  // not in the tree, we can see consider continuing on the disk
71
70
  if (!parent.source)
72
71
  return; // but then we need the current node to be linked to the disk, otherwise, we give up
@@ -83,13 +82,16 @@ async function urlToNode(url, ctx, parent = exports.vfs) {
83
82
  if (parent.default)
84
83
  inheritFromParent({ mime: { '*': exports.MIME_AUTO } }, ret);
85
84
  if (rest)
86
- return urlToNode(rest, ctx, ret);
85
+ return urlToNode(rest, ctx, ret, getRest);
87
86
  if (ret.source)
88
87
  try {
89
88
  await promises_1.default.stat(ret.source);
90
89
  } // check existence
91
90
  catch (_b) {
92
- return;
91
+ if (!getRest)
92
+ return;
93
+ getRest(onDisk);
94
+ return parent;
93
95
  }
94
96
  return ret;
95
97
  }
@@ -115,18 +117,21 @@ exports.nodeIsDirectory = nodeIsDirectory;
115
117
  function hasPermission(node, perm, ctx) {
116
118
  var _a;
117
119
  return matchWho((_a = node[perm]) !== null && _a !== void 0 ? _a : exports.defaultPerms[perm], ctx)
118
- && (perm !== 'can_see' || hasPermission(node, 'can_read', ctx)); // for can_see you must also can_read
120
+ && (perm !== 'can_see' || hasPermission(node, 'can_read', ctx)); // can_see is used to hide something you nonetheless can_read, so you MUST also can_read
119
121
  }
120
122
  exports.hasPermission = hasPermission;
121
123
  async function* walkNode(parent, ctx, depth = 0, prefixPath = '') {
122
124
  var _a;
123
125
  const { children, source } = parent;
126
+ const took = prefixPath ? undefined : new Set();
124
127
  if (children)
125
128
  for (let idx = 0; idx < children.length; idx++) {
126
129
  const child = children[idx];
130
+ const name = prefixPath + getNodeName(child);
131
+ took === null || took === void 0 ? void 0 : took.add(name);
127
132
  yield* workItem({
128
133
  ...child,
129
- name: prefixPath ? (prefixPath + getNodeName(child)) : child.name
134
+ name,
130
135
  }, depth > 0 && await nodeIsDirectory(child).catch(() => false));
131
136
  }
132
137
  if (!source)
@@ -135,9 +140,11 @@ async function* walkNode(parent, ctx, depth = 0, prefixPath = '') {
135
140
  for await (const path of (0, misc_1.dirStream)(source, depth)) {
136
141
  if (ctx === null || ctx === void 0 ? void 0 : ctx.req.aborted)
137
142
  return;
138
- const renamed = (_a = parent.rename) === null || _a === void 0 ? void 0 : _a[path];
143
+ const name = prefixPath + (((_a = parent.rename) === null || _a === void 0 ? void 0 : _a[path]) || path);
144
+ if (took === null || took === void 0 ? void 0 : took.has(name))
145
+ continue;
139
146
  yield* workItem({
140
- name: prefixPath + (renamed || path),
147
+ name,
141
148
  source: (0, path_1.join)(source, path),
142
149
  rename: renameUnderPath(parent.rename, path),
143
150
  });
@@ -151,12 +158,7 @@ async function* walkNode(parent, ctx, depth = 0, prefixPath = '') {
151
158
  const name = getNodeName(item);
152
159
  // we basename for depth>0 where we already have the rest of the path in the parent's url, and would be duplicated
153
160
  const virtualBasename = (0, path_1.basename)(name);
154
- const url = (0, misc_1.enforceFinal)('/', parent.url || '') + virtualBasename;
155
- Object.assign(item, {
156
- isTemp: true,
157
- url,
158
- parents: [...parent.parents || [], parent],
159
- });
161
+ item.isTemp = true;
160
162
  inheritFromParent(parent, item);
161
163
  applyMasks(item, parent, virtualBasename);
162
164
  if (ctx && !hasPermission(item, 'can_see', ctx))
@@ -206,7 +208,7 @@ function matchWho(who, ctx) {
206
208
  (0, misc_1.getOrSet)(ctx.state, 'usernames', () => (0, perm_1.getCurrentUsernameExpanded)(ctx)).some((u) => who.includes(u)))();
207
209
  }
208
210
  function cantReadStatusCode(node) {
209
- return node.can_read === false ? const_1.FORBIDDEN : const_1.UNAUTHORIZED;
211
+ return node.can_read === false ? const_1.HTTP_FORBIDDEN : const_1.HTTP_UNAUTHORIZED;
210
212
  }
211
213
  exports.cantReadStatusCode = cantReadStatusCode;
212
214
  events_1.default.on('accountRenamed', (from, to) => {
@@ -214,8 +216,8 @@ events_1.default.on('accountRenamed', (from, to) => {
214
216
  saveVfs();
215
217
  function recur(n) {
216
218
  var _a;
217
- replace(n.can_see);
218
- replace(n.can_read);
219
+ for (const k of (0, misc_1.typedKeys)(exports.defaultPerms))
220
+ replace(n[k]);
219
221
  if (n.masks)
220
222
  Object.values(n.masks).forEach(recur);
221
223
  (_a = n.children) === null || _a === void 0 ? void 0 : _a.forEach(recur);
package/src/watchLoad.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
+ // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
3
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
package/src/zip.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
+ // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
3
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
@@ -13,8 +13,9 @@ const promises_1 = __importDefault(require("fs/promises"));
13
13
  const config_1 = require("./config");
14
14
  const path_1 = require("path");
15
15
  const serveFile_1 = require("./serveFile");
16
+ const const_1 = require("./const");
16
17
  async function zipStreamFromFolder(node, ctx) {
17
- ctx.status = 200;
18
+ ctx.status = const_1.HTTP_OK;
18
19
  ctx.mime = 'zip';
19
20
  const name = (0, vfs_1.getNodeName)(node);
20
21
  ctx.attachment((name || 'archive') + '.zip');