hfs 0.42.2 → 0.43.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.
Files changed (43) hide show
  1. package/README.md +9 -12
  2. package/admin/assets/index-5cd667a5.js +511 -0
  3. package/admin/assets/index-8ff39373.css +1 -0
  4. package/{frontend/assets/sha512-bce9fb1c.js → admin/assets/sha512-55ff2fa3.js} +1 -1
  5. package/admin/index.html +2 -2
  6. package/frontend/assets/index-27488fde.js +94 -0
  7. package/frontend/assets/index-54a5c76f.css +1 -0
  8. package/{admin/assets/sha512-af87c1bd.js → frontend/assets/sha512-8ebf6e2a.js} +1 -1
  9. package/frontend/fontello.css +9 -3
  10. package/frontend/fontello.woff2 +0 -0
  11. package/frontend/index.html +2 -2
  12. package/package.json +2 -2
  13. package/plugins/antibrute/plugin.js +1 -1
  14. package/plugins/download-counter/plugin.js +10 -3
  15. package/plugins/download-counter/public/main.js +12 -2
  16. package/src/adminApis.js +3 -3
  17. package/src/api.accounts.js +2 -1
  18. package/src/api.file_list.js +15 -2
  19. package/src/api.lang.js +8 -11
  20. package/src/api.vfs.js +11 -5
  21. package/src/block.js +6 -20
  22. package/src/config.js +6 -2
  23. package/src/const.js +2 -2
  24. package/src/customHtml.js +1 -1
  25. package/src/frontEndApis.js +1 -26
  26. package/src/lang.js +77 -0
  27. package/src/langs/hfs-lang-it.json +100 -0
  28. package/src/langs/hfs-lang-ko.json +103 -0
  29. package/src/langs/hfs-lang-ru.json +106 -0
  30. package/src/langs/hfs-lang-sr.json +108 -0
  31. package/src/langs/hfs-lang-zh.json +98 -0
  32. package/src/listen.js +8 -3
  33. package/src/middlewares.js +10 -0
  34. package/src/misc.js +13 -9
  35. package/src/perm.js +1 -1
  36. package/src/serveFile.js +2 -2
  37. package/src/serveGuiFiles.js +21 -8
  38. package/src/upload.js +1 -1
  39. package/src/vfs.js +27 -33
  40. package/admin/assets/index-1db4299e.js +0 -511
  41. package/admin/assets/index-94bbe0be.css +0 -1
  42. package/frontend/assets/index-297a3f3d.js +0 -94
  43. package/frontend/assets/index-a09cacfd.css +0 -1
package/src/serveFile.js CHANGED
@@ -33,6 +33,8 @@ function serveFileNode(ctx, node) {
33
33
  }
34
34
  }
35
35
  ctx.vfsNode = node; // useful to tell service files from files shared by the user
36
+ if ('dl' in ctx.params) // please, download
37
+ ctx.attachment(name);
36
38
  return serveFile(ctx, source || '', mimeString);
37
39
  }
38
40
  exports.serveFileNode = serveFileNode;
@@ -41,8 +43,6 @@ async function serveFile(ctx, source, mime, content) {
41
43
  if (!source)
42
44
  return;
43
45
  const fn = path_1.default.basename(source);
44
- if ('dl' in ctx.params) // please, download
45
- ctx.attachment(fn);
46
46
  mime = mime !== null && mime !== void 0 ? mime : lodash_1.default.find(mimeCfg.get(), (v, k) => (0, misc_1.matches)(fn, k));
47
47
  if (mime === vfs_1.MIME_AUTO)
48
48
  mime = mime_types_1.default.lookup(source) || '';
@@ -41,6 +41,7 @@ const valtio_1 = require("valtio");
41
41
  const customHtml_1 = require("./customHtml");
42
42
  const lodash_1 = __importDefault(require("lodash"));
43
43
  const config_1 = require("./config");
44
+ const lang_1 = require("./lang");
44
45
  // in case of dev env we have our static files within the 'dist' folder'
45
46
  const DEV_STATIC = process.env.DEV ? 'dist/' : '';
46
47
  function serveStatic(uri) {
@@ -68,8 +69,6 @@ function serveStatic(uri) {
68
69
  return (0, serveFile_1.serveFile)(ctx, fullPath, 'auto', content);
69
70
  // we don't cache the index as it's small and may prevent plugins change to apply
70
71
  ctx.body = await treatIndex(ctx, uri, String(content));
71
- ctx.type = 'html';
72
- ctx.set('Cache-Control', 'no-store, no-cache, must-revalidate');
73
72
  };
74
73
  }
75
74
  function shouldServeApp(ctx) {
@@ -84,10 +83,10 @@ function adjustBundlerLinks(ctx, uri, data) {
84
83
  async function treatIndex(ctx, filesUri, body) {
85
84
  const session = await (0, api_auth_1.refresh_session)({}, ctx);
86
85
  ctx.set('etag', '');
86
+ ctx.set('Cache-Control', 'no-store, no-cache, must-revalidate');
87
+ ctx.type = 'html';
87
88
  const isFrontend = filesUri === const_1.FRONTEND_URI;
88
89
  const pub = ctx.state.revProxyPath + const_1.PLUGINS_PUB_URI;
89
- const css = (0, plugins_1.mapPlugins)((plug, k) => { var _a; return (_a = (isFrontend ? plug.frontend_css : null)) === null || _a === void 0 ? void 0 : _a.map(f => pub + k + '/' + f); }).flat().filter(Boolean);
90
- const js = (0, plugins_1.mapPlugins)((plug, k) => { var _a; return (_a = (isFrontend ? plug.frontend_js : null)) === null || _a === void 0 ? void 0 : _a.map(f => pub + k + '/' + f); }).flat().filter(Boolean);
91
90
  // expose plugins' configs that are declared with 'frontend' attribute
92
91
  const plugins = Object.fromEntries((0, misc_1.onlyTruthy)((0, plugins_1.mapPlugins)((pl, name) => {
93
92
  var _a, _b;
@@ -99,6 +98,7 @@ async function treatIndex(ctx, filesUri, body) {
99
98
  configs = ((_b = (_a = (0, plugins_1.getPluginInfo)(name)).onFrontendConfig) === null || _b === void 0 ? void 0 : _b.call(_a, configs)) || configs;
100
99
  return !lodash_1.default.isEmpty(configs) && [name, configs];
101
100
  })));
101
+ const lang = await (0, lang_1.getLangData)(ctx);
102
102
  let ret = body
103
103
  .replace(/((?:src|href) *= *['"])\/?(?![a-z]+:\/\/)/g, '$1' + ctx.state.revProxyPath + filesUri)
104
104
  .replace('</head>', () => `
@@ -115,17 +115,30 @@ async function treatIndex(ctx, filesUri, body) {
115
115
  plugins,
116
116
  prefixUrl: ctx.state.revProxyPath,
117
117
  customHtml: lodash_1.default.omit(Object.fromEntries(customHtml_1.customHtmlState.sections), ['top', 'bottom']),
118
- fileMenuOnLink: fileMenuOnLink.get()
119
- }, null, 4)}
118
+ fileMenuOnLink: fileMenuOnLink.get(),
119
+ lang
120
+ }, null, 4)
121
+ .replace(/<(\/script)/g, '<"+"$1') /*avoid breaking our script container*/}
120
122
  document.documentElement.setAttribute('ver', '${const_1.VERSION.split('-')[0] /*for style selectors*/}')
123
+ HFS.getPluginKey = () => document.currentScript?.getAttribute('plugin')
124
+ || console.error("this function must be called at the very top of your file")
125
+ HFS.getPluginConfig = () => HFS.plugins[HFS.getPluginKey()]
121
126
  </script>
122
127
  <style>
123
128
  :root {
124
129
  ${lodash_1.default.map(plugins, (configs, pluginName) => lodash_1.default.map(configs, (v, k) => `--${pluginName}-${k}: ${serializeCss(v)};`).join('\n')).join('')}
125
130
  }
126
131
  </style>
127
- ${css.map(uri => `<link rel='stylesheet' type='text/css' href='${uri}'/>`).join('\n')}
128
- ${js.map(uri => `<script defer src='${uri}'></script>`).join('\n')}
132
+ ${!isFrontend ? '' : (0, plugins_1.mapPlugins)((plug, k) => {
133
+ var _a;
134
+ return (_a = plug.frontend_css) === null || _a === void 0 ? void 0 : _a.map(f => `<link rel='stylesheet' type='text/css' href='${pub + k + '/' + f}' plugin=${JSON.stringify(k)}/>`);
135
+ })
136
+ .flat().filter(Boolean).join('\n')}
137
+ ${!isFrontend ? '' : (0, plugins_1.mapPlugins)((plug, k) => {
138
+ var _a;
139
+ return (_a = plug.frontend_js) === null || _a === void 0 ? void 0 : _a.map(f => `<script defer plugin=${JSON.stringify(k)} src='${pub + k + '/' + f}'></script>`);
140
+ })
141
+ .flat().filter(Boolean).join('\n')}
129
142
  </head>`);
130
143
  if (isFrontend)
131
144
  ret = ret
package/src/upload.js CHANGED
@@ -15,7 +15,7 @@ const util_os_1 = require("./util-os");
15
15
  const connections_1 = require("./connections");
16
16
  const throttler_1 = require("./throttler");
17
17
  const lodash_1 = __importDefault(require("lodash"));
18
- exports.deleteUnfinishedUploadsAfter = (0, config_1.defineConfig)('delete_unfinished_uploads_after');
18
+ exports.deleteUnfinishedUploadsAfter = (0, config_1.defineConfig)('delete_unfinished_uploads_after', undefined);
19
19
  exports.minAvailableMb = (0, config_1.defineConfig)('min_available_mb', 100);
20
20
  const dontOverwriteUploading = (0, config_1.defineConfig)('dont_overwrite_uploading', false);
21
21
  const waitingToBeDeleted = {};
package/src/vfs.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.walkNode = exports.statusCodeForMissingPerm = exports.hasPermission = exports.nodeIsDirectory = exports.getNodeName = exports.saveVfs = exports.vfs = exports.urlToNode = exports.isSameFilenameAs = exports.MIME_AUTO = exports.defaultPerms = void 0;
7
+ exports.masksCouldGivePermission = exports.walkNode = exports.statusCodeForMissingPerm = exports.hasPermission = exports.nodeIsDirectory = exports.getNodeName = exports.saveVfs = exports.vfs = exports.urlToNode = exports.isSameFilenameAs = exports.MIME_AUTO = exports.defaultPerms = exports.WHO_ANY_ACCOUNT = exports.WHO_NO_ONE = exports.WHO_ANYONE = void 0;
8
8
  const promises_1 = __importDefault(require("fs/promises"));
9
9
  const path_1 = require("path");
10
10
  const misc_1 = require("./misc");
@@ -13,15 +13,15 @@ const config_1 = require("./config");
13
13
  const const_1 = require("./const");
14
14
  const events_1 = __importDefault(require("./events"));
15
15
  const perm_1 = require("./perm");
16
- const WHO_ANYONE = true;
17
- const WHO_NO_ONE = false;
18
- const WHO_ANY_ACCOUNT = '*';
16
+ exports.WHO_ANYONE = true;
17
+ exports.WHO_NO_ONE = false;
18
+ exports.WHO_ANY_ACCOUNT = '*';
19
19
  exports.defaultPerms = {
20
- can_see: WHO_ANYONE,
21
- can_read: WHO_ANYONE,
22
- can_list: WHO_ANYONE,
23
- can_upload: WHO_NO_ONE,
24
- can_delete: WHO_NO_ONE,
20
+ can_see: exports.WHO_ANYONE,
21
+ can_read: exports.WHO_ANYONE,
22
+ can_list: exports.WHO_ANYONE,
23
+ can_upload: exports.WHO_NO_ONE,
24
+ can_delete: exports.WHO_NO_ONE,
25
25
  };
26
26
  exports.MIME_AUTO = 'auto';
27
27
  function inheritFromParent(parent, child) {
@@ -104,16 +104,18 @@ function saveVfs() {
104
104
  }
105
105
  exports.saveVfs = saveVfs;
106
106
  function getNodeName(node) {
107
- const { name, source: s } = node;
107
+ const { name, source } = node;
108
108
  if (name)
109
109
  return name;
110
- if (!s)
110
+ if (!source)
111
111
  return ''; // should happen only for root
112
- if (/^[a-zA-Z]:\\?$/.test(s))
113
- return s.slice(0, 2); // exclude trailing slash
114
- const base = (0, path_1.basename)(s);
112
+ if (source === '/')
113
+ return 'root';
114
+ if (/^[a-zA-Z]:\\?$/.test(source))
115
+ return source.slice(0, 2); // exclude trailing slash
116
+ const base = (0, path_1.basename)(source);
115
117
  if (/^[./\\]*$/.test(base)) // if empty or special-chars-only
116
- return (0, path_1.basename)((0, path_1.resolve)(s)); // resolve to try to get more
118
+ return (0, path_1.basename)((0, path_1.resolve)(source)); // resolve to try to get more
117
119
  return base;
118
120
  }
119
121
  exports.getNodeName = getNodeName;
@@ -137,10 +139,6 @@ exports.statusCodeForMissingPerm = statusCodeForMissingPerm;
137
139
  // Too many parameters: consider object, but benchmark against degraded recursion on huge folders.
138
140
  async function* walkNode(parent, ctx, depth = 0, prefixPath = '', requiredPerm) {
139
141
  var _a;
140
- if (requiredPerm && ctx
141
- && !hasPermission(parent, requiredPerm, ctx)
142
- && !masksCouldGivePermission(parent.masks))
143
- return; // no permission, no reason to continue
144
142
  const { children, source } = parent;
145
143
  const took = prefixPath ? undefined : new Set();
146
144
  if (children)
@@ -160,6 +158,10 @@ async function* walkNode(parent, ctx, depth = 0, prefixPath = '', requiredPerm)
160
158
  }
161
159
  if (!source)
162
160
  return;
161
+ if (requiredPerm && ctx // no permission, no reason to continue (at least for dynamic elements)
162
+ && !hasPermission(parent, requiredPerm, ctx)
163
+ && !masksCouldGivePermission(parent.masks, requiredPerm))
164
+ return;
163
165
  try {
164
166
  let lastDir = prefixPath.slice(0, -1) || '.';
165
167
  const map = new Map();
@@ -201,20 +203,12 @@ async function* walkNode(parent, ctx, depth = 0, prefixPath = '', requiredPerm)
201
203
  item.isTemp = true;
202
204
  return item;
203
205
  }
204
- function masksCouldGivePermission(masks) {
205
- if (!masks)
206
- return false;
207
- for (const [, props] of Object.entries(masks)) {
208
- const v = props[requiredPerm];
209
- if (v && (!ctx || matchWho(v, ctx))) // without ctx we can't say, so it could
210
- return true;
211
- if (masksCouldGivePermission(props.masks))
212
- return true;
213
- }
214
- return false;
215
- }
216
206
  }
217
207
  exports.walkNode = walkNode;
208
+ function masksCouldGivePermission(masks, perm) {
209
+ return masks !== undefined && Object.values(masks).some(props => props[perm] || masksCouldGivePermission(props.masks, perm));
210
+ }
211
+ exports.masksCouldGivePermission = masksCouldGivePermission;
218
212
  function applyMasks(item, parent, virtualBasename) {
219
213
  const { masks } = parent;
220
214
  if (!masks)
@@ -246,8 +240,8 @@ function renameUnderPath(rename, path) {
246
240
  return lodash_1.default.isEmpty(rename) ? undefined : rename;
247
241
  }
248
242
  function matchWho(who, ctx) {
249
- return who === WHO_ANYONE
250
- || who === WHO_ANY_ACCOUNT && Boolean(ctx.state.account)
243
+ return who === exports.WHO_ANYONE
244
+ || who === exports.WHO_ANY_ACCOUNT && Boolean(ctx.state.account)
251
245
  || Array.isArray(who) // check if I or any ancestor match `who`, but cache ancestors' usernames inside context state
252
246
  && (0, misc_1.getOrSet)(ctx.state, 'usernames', () => (0, perm_1.getCurrentUsernameExpanded)(ctx)).some((u) => who.includes(u));
253
247
  }