hfs 0.53.0-alpha2 → 0.53.0-alpha3

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
- System.register(["./index-legacy-C21Ot_ue.js"],(function(h,t){"use strict";var i,s;return{setters:[function(h){i=h.g,s=h.c}],execute:function(){function t(h,t){for(var i=function(){var i=t[s];if("string"!=typeof i&&!Array.isArray(i)){var r=function(t){if("default"!==t&&!(t in h)){var s=Object.getOwnPropertyDescriptor(i,t);s&&Object.defineProperty(h,t,s.get?s:{enumerable:!0,get:function(){return i[t]}})}};for(var e in i)r(e)}},s=0;s<t.length;s++)i();return Object.freeze(Object.defineProperty(h,Symbol.toStringTag,{value:"Module"}))}var r={exports:{}};
1
+ System.register(["./index-legacy-BzpvPuwE.js"],(function(h,t){"use strict";var i,s;return{setters:[function(h){i=h.g,s=h.c}],execute:function(){function t(h,t){for(var i=function(){var i=t[s];if("string"!=typeof i&&!Array.isArray(i)){var r=function(t){if("default"!==t&&!(t in h)){var s=Object.getOwnPropertyDescriptor(i,t);s&&Object.defineProperty(h,t,s.get?s:{enumerable:!0,get:function(){return i[t]}})}};for(var e in i)r(e)}},s=0;s<t.length;s++)i();return Object.freeze(Object.defineProperty(h,Symbol.toStringTag,{value:"Module"}))}var r={exports:{}};
2
2
  /*
3
3
  * [js-sha512]{@link https://github.com/emn178/js-sha512}
4
4
  *
@@ -7,10 +7,10 @@
7
7
 
8
8
  </head>
9
9
  <body>
10
- <noscript>You need to enable JavaScript to run this app.</noscript>
10
+ <noscript>Enable JavaScript or <a href="?get=basic">go simple</a></noscript>
11
11
  <div id="root"></div>
12
12
  <script nomodule>document.getElementById('root').innerText = "Please use a newer browser"</script>
13
13
  <script crossorigin id="vite-legacy-polyfill" src="/assets/polyfills-legacy-DMrMt_pQ.js"></script>
14
- <script crossorigin id="vite-legacy-entry" data-src="/assets/index-legacy-C21Ot_ue.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
14
+ <script crossorigin id="vite-legacy-entry" data-src="/assets/index-legacy-BzpvPuwE.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
15
15
  </body>
16
16
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hfs",
3
- "version": "0.53.0-alpha2",
3
+ "version": "0.53.0-alpha3",
4
4
  "description": "HTTP File Server",
5
5
  "keywords": [
6
6
  "file server",
@@ -71,6 +71,7 @@
71
71
  "dependencies": {
72
72
  "@koa/router": "^12.0.1",
73
73
  "@node-rs/crc32": "^1.6.0",
74
+ "@rejetto/kvstorage": "^0.4.0",
74
75
  "acme-client": "^5.2.0",
75
76
  "basic-auth": "^2.0.1",
76
77
  "buffer-crc32": "^0.2.13",
@@ -71,7 +71,7 @@ exports.default = {
71
71
  : s.uploadPath ? { op: 'upload', path: decodeURIComponent(s.uploadPath) }
72
72
  : {
73
73
  op: !s.considerAsGui && s.op || undefined,
74
- path: decodeURIComponent(ctx.originalUrl)
74
+ path: (0, misc_1.try_)(() => decodeURIComponent(ctx.originalUrl), () => ctx.originalUrl),
75
75
  },
76
76
  opProgress: lodash_1.default.isNumber(s.opProgress) ? lodash_1.default.round(s.opProgress, 3) : undefined,
77
77
  opTotal: s.opTotal,
package/src/api.net.js CHANGED
@@ -17,6 +17,7 @@ const acme_1 = require("./acme");
17
17
  const selfCheck_1 = require("./selfCheck");
18
18
  const apis = {
19
19
  get_nat: nat_1.getNatInfo,
20
+ get_public_ips: nat_1.getPublicIps,
20
21
  async check_domain({ domain }) {
21
22
  (0, misc_1.apiAssertTypes)({ string: domain });
22
23
  const resolver = new promises_1.Resolver();
@@ -63,15 +64,15 @@ const apis = {
63
64
  if (url)
64
65
  return await (0, selfCheck_1.selfCheck)(url)
65
66
  || new apiMiddleware_1.ApiError(const_1.HTTP_SERVICE_UNAVAILABLE);
66
- const nat = await (0, nat_1.getNatInfo)();
67
- if (!nat.publicIps.length)
67
+ const [publicIps, nat] = await Promise.all([(0, nat_1.getPublicIps)(), (0, nat_1.getNatInfo)()]);
68
+ if (!publicIps.length)
68
69
  return new apiMiddleware_1.ApiError(const_1.HTTP_FAILED_DEPENDENCY, 'cannot detect public ip');
69
70
  if (!nat.internalPort)
70
71
  return new apiMiddleware_1.ApiError(const_1.HTTP_FAILED_DEPENDENCY, 'no internal port');
71
72
  const finalPort = nat.externalPort || nat.internalPort;
72
73
  const proto = nat.proto || ((0, listen_1.getCertObject)() ? 'https' : 'http');
73
74
  const defPort = proto === 'https' ? 443 : 80;
74
- const results = (0, misc_1.onlyTruthy)(await (0, misc_1.promiseBestEffort)(nat.publicIps.map(ip => (0, selfCheck_1.selfCheck)(`${proto}://${ip}${finalPort === defPort ? '' : ':' + finalPort}`))));
75
+ const results = (0, misc_1.onlyTruthy)(await (0, misc_1.promiseBestEffort)(publicIps.map(ip => (0, selfCheck_1.selfCheck)(`${proto}://${ip}${finalPort === defPort ? '' : ':' + finalPort}`))));
75
76
  return results.length ? results : new apiMiddleware_1.ApiError(const_1.HTTP_SERVICE_UNAVAILABLE);
76
77
  },
77
78
  async make_cert({ domain, email, altNames }) {
@@ -36,19 +36,9 @@ function apiMiddleware(apis) {
36
36
  // we don't rely on SameSite cookie option because it's https-only
37
37
  let res;
38
38
  try {
39
- if (ctx.state.revProxyPath)
40
- for (const [k, v] of Object.entries(params))
41
- if (k.startsWith('uri'))
42
- if (typeof v === 'string')
43
- fixUri(params, k);
44
- else if (typeof (v === null || v === void 0 ? void 0 : v[0]) === 'string')
45
- v.forEach((x, i) => fixUri(v, i));
46
39
  res = await apiFun(params, ctx);
47
40
  if (res === null)
48
41
  return;
49
- function fixUri(obj, k) {
50
- obj[k] = (0, misc_1.removeStarting)(ctx.state.revProxyPath, obj[k]);
51
- }
52
42
  }
53
43
  catch (e) {
54
44
  if (typeof e === 'string') // message meant to be transmitted
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.basicWeb = void 0;
7
+ const auth_1 = require("./auth");
8
+ const cross_const_1 = require("./cross-const");
9
+ const config_1 = require("./config");
10
+ const vfs_1 = require("./vfs");
11
+ const misc_1 = require("./misc");
12
+ const lodash_1 = __importDefault(require("lodash"));
13
+ const adminApis_1 = require("./adminApis");
14
+ const customHtml_1 = require("./customHtml");
15
+ const autoBasic = (0, config_1.defineConfig)('auto_basic', true);
16
+ function basicWeb(ctx, node) {
17
+ const { get } = ctx.query;
18
+ if (get === 'login') {
19
+ if ((0, auth_1.getCurrentUsername)(ctx))
20
+ ctx.redirect('?');
21
+ else {
22
+ ctx.set('WWW-Authenticate', 'Basic');
23
+ ctx.status = cross_const_1.HTTP_UNAUTHORIZED;
24
+ }
25
+ return true;
26
+ }
27
+ if (get === 'logout') {
28
+ ctx.body = `<script>location = '?'</script>`;
29
+ (0, auth_1.setLoggedIn)(ctx, false);
30
+ ctx.status = cross_const_1.HTTP_UNAUTHORIZED;
31
+ return true;
32
+ }
33
+ const forced = get === 'basic';
34
+ if (forced || detectBasicAgent()) {
35
+ ctx.type = 'html';
36
+ const force = forced ? '?get=basic' : '';
37
+ const walker = (0, vfs_1.walkNode)(node, { ctx, depth: 0 });
38
+ const stream = (0, misc_1.asyncGeneratorToReadable)((0, misc_1.filterMapGenerator)(walker, async (el) => {
39
+ const isFolder = await (0, vfs_1.nodeIsDirectory)(el);
40
+ const name = (0, vfs_1.getNodeName)(el) + (isFolder ? '/' : '');
41
+ return `<li>${a((0, misc_1.pathEncode)(name) + (isFolder ? force : ''), name)}\n`;
42
+ }));
43
+ ctx.body = stream;
44
+ stream.push(`<title>${adminApis_1.title.get()}</title><body>`);
45
+ stream.push((0, customHtml_1.getSection)('basicHeader'));
46
+ const links = (0, auth_1.getCurrentUsername)(ctx) ? { '?get=logout': "Logout" } : { '?get=login': "Login" };
47
+ stream.push(lodash_1.default.map(links, (v, k) => a(k, v)).join(' ') + '\n<ul>\n');
48
+ if (ctx.state.originalPath.length > 1)
49
+ stream.push('<li>' + a('..' + force, '..') + '\n');
50
+ stream.push('</ul>\n');
51
+ stream.push((0, customHtml_1.getSection)('basicFooter'));
52
+ return true;
53
+ }
54
+ function a(href, label) {
55
+ return `<a href='${href}'>${label}</a>`;
56
+ }
57
+ function detectBasicAgent() {
58
+ const ua = ctx.get('user-agent');
59
+ const v = autoBasic.get();
60
+ return v && (/Mozilla\/4|WebKit\/([234]\d\d|5[012]\d|53[0123456])[. ]|Trident|Lynx|Firefox\/(\d|[123]\d)\./.test(ua)
61
+ || lodash_1.default.isString(v) && ua.includes(v));
62
+ }
63
+ }
64
+ exports.basicWeb = basicWeb;
package/src/const.js CHANGED
@@ -37,7 +37,7 @@ const os_1 = require("os");
37
37
  const fs_1 = require("fs");
38
38
  const path_1 = require("path");
39
39
  __exportStar(require("./cross-const"), exports);
40
- exports.API_VERSION = 8.8;
40
+ exports.API_VERSION = 8.81;
41
41
  exports.COMPATIBLE_API_VERSION = 1; // while changes in the api are not breaking, this number stays the same, otherwise it is made equal to API_VERSION
42
42
  exports.HFS_REPO = 'rejetto/hfs';
43
43
  exports.argv = (0, minimist_1.default)(process.argv.slice(2));
@@ -45,7 +45,7 @@ exports.DEV = process.env.DEV || exports.argv.dev ? 'DEV' : '';
45
45
  exports.ORIGINAL_CWD = process.cwd();
46
46
  exports.HFS_STARTED = new Date();
47
47
  const PKG_PATH = (0, path_1.join)(__dirname, '..', 'package.json');
48
- exports.BUILD_TIMESTAMP = "2024-05-08T10:54:50.461Z";
48
+ exports.BUILD_TIMESTAMP = "2024-05-15T10:18:26.357Z";
49
49
  const pkg = JSON.parse(fs.readFileSync(PKG_PATH, 'utf8'));
50
50
  exports.VERSION = pkg.version;
51
51
  exports.RUNNING_BETA = exports.VERSION.includes('-');
package/src/cross.js CHANGED
@@ -17,8 +17,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.typedEntries = exports.typedKeys = exports.objRenameKey = exports.randomId = exports.getOrSet = exports.waitFor = exports.newObj = exports.findDefined = exports.isOrderedEqual = exports.swap = exports.tryJson = exports.dirname = exports.basename = exports.pendingPromise = exports._dbg = exports._log = exports.wantArray = exports.formatPerc = exports.with_ = exports.try_ = exports.setHidden = exports.onlyTruthy = exports.truthy = exports.splitAt = exports.strinsert = exports.removeStarting = exports.enforceFinal = exports.objSameKeys = exports.haveTimeout = exports.wait = exports.prefix = exports.formatSpeed = exports.formatBytes = exports.isWhoObject = exports.PERM_KEYS = exports.defaultPerms = exports.WHO_ANY_ACCOUNT = exports.WHO_NO_ONE = exports.WHO_ANYONE = exports.LIST = exports.CFG = exports.THEME_OPTIONS = exports.SORT_BY_OPTIONS = exports.FRONTEND_OPTIONS = exports.MAX_TILE_SIZE = exports.DAY = exports.HOUR = exports.MINUTE = exports.WIKI_URL = exports.REPO_URL = void 0;
21
- exports.shortenAgent = exports.mapFilter = exports.inCommon = exports.replace = exports.matches = exports.makeMatcher = exports.runAt = exports.pathEncode = exports.promiseBestEffort = exports.escapeHTML = exports.ipForUrl = exports.isIpLan = exports.isIpLocalHost = exports.xlate = exports.isEqualLax = exports.isTimestampString = exports.isWindowsDrive = exports.isIP = exports.isPrimitive = exports.formatTimestamp = exports.repeat = exports.asyncGeneratorToArray = exports.filterMapGenerator = exports.throw_ = exports.hasProp = void 0;
20
+ exports.objRenameKey = exports.randomId = exports.getOrSet = exports.waitFor = exports.newObj = exports.findDefined = exports.isOrderedEqual = exports.swap = exports.tryJson = exports.dirname = exports.basename = exports.pendingPromise = exports._dbg = exports._log = exports.wantArray = exports.formatPerc = exports.with_ = exports.try_ = exports.setHidden = exports.onlyTruthy = exports.truthy = exports.splitAt = exports.strinsert = exports.removeStarting = exports.enforceStarting = exports.enforceFinal = exports.objSameKeys = exports.haveTimeout = exports.wait = exports.join = exports.prefix = exports.formatSpeed = exports.formatBytes = exports.isWhoObject = exports.PERM_KEYS = exports.defaultPerms = exports.WHO_ANY_ACCOUNT = exports.WHO_NO_ONE = exports.WHO_ANYONE = exports.LIST = exports.CFG = exports.THEME_OPTIONS = exports.SORT_BY_OPTIONS = exports.FRONTEND_OPTIONS = exports.MAX_TILE_SIZE = exports.DAY = exports.HOUR = exports.MINUTE = exports.WIKI_URL = exports.REPO_URL = void 0;
21
+ exports.shortenAgent = exports.mapFilter = exports.inCommon = exports.replace = exports.matches = exports.makeMatcher = exports.runAt = exports.pathEncode = exports.promiseBestEffort = exports.escapeHTML = exports.ipForUrl = exports.isIpLan = exports.isIpLocalHost = exports.xlate = exports.isEqualLax = exports.isTimestampString = exports.isWindowsDrive = exports.isIP = exports.isPrimitive = exports.formatTimestamp = exports.repeat = exports.asyncGeneratorToArray = exports.filterMapGenerator = exports.throw_ = exports.hasProp = exports.typedEntries = exports.typedKeys = void 0;
22
22
  // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
23
23
  // all content here is shared between client and server
24
24
  const lodash_1 = __importDefault(require("lodash"));
@@ -85,6 +85,16 @@ function prefix(pre, v, post = '') {
85
85
  return v ? (pre || '') + v + (post || '') : '';
86
86
  }
87
87
  exports.prefix = prefix;
88
+ function join(a, b, joiner = '/') {
89
+ if (!b)
90
+ return a;
91
+ if (!a)
92
+ return b;
93
+ const ends = a.at(-1) === joiner;
94
+ const starts = b[0] === joiner;
95
+ return a + (!ends && !starts ? joiner + b : ends && starts ? b.slice(1) : b);
96
+ }
97
+ exports.join = join;
88
98
  function wait(ms, val) {
89
99
  return new Promise(res => setTimeout(res, ms, val));
90
100
  }
@@ -98,9 +108,13 @@ function objSameKeys(src, newValue) {
98
108
  }
99
109
  exports.objSameKeys = objSameKeys;
100
110
  function enforceFinal(sub, s, evenEmpty = false) {
101
- return !evenEmpty && !s || s.endsWith(sub) ? s : s + sub;
111
+ return evenEmpty && !s || !s.endsWith(sub) ? s + sub : s;
102
112
  }
103
113
  exports.enforceFinal = enforceFinal;
114
+ function enforceStarting(sub, s, evenEmpty = false) {
115
+ return evenEmpty && !s || !s.startsWith(sub) ? sub + s : s;
116
+ }
117
+ exports.enforceStarting = enforceStarting;
104
118
  function removeStarting(sub, s) {
105
119
  return s.startsWith(sub) ? s.slice(sub.length) : s;
106
120
  }
package/src/github.js CHANGED
@@ -165,20 +165,26 @@ async function* apiGithubPaginated(uri) {
165
165
  const PAGE_SIZE = 100;
166
166
  let page = 1;
167
167
  let n = 0;
168
- while (1) {
169
- const res = await apiGithub(uri + `&page=${page++}&per_page=${PAGE_SIZE}`);
170
- for (const x of res.items)
171
- yield x;
172
- const now = res.items.length;
173
- n += now;
174
- if (!now || n >= res.total_count)
175
- break;
168
+ try {
169
+ while (1) {
170
+ const res = await apiGithub(uri + `&page=${page++}&per_page=${PAGE_SIZE}`);
171
+ for (const x of res.items)
172
+ yield x;
173
+ const now = res.items.length;
174
+ n += now;
175
+ if (!now || n >= res.total_count)
176
+ break;
177
+ }
178
+ }
179
+ catch (e) {
180
+ if (e.message !== '422') // for some strange reason github api is returning this error if we search repos for a missing user, instead of empty set
181
+ throw e;
176
182
  }
177
183
  }
178
184
  async function searchPlugins(text = '', { skipRepos = [''] } = {}) {
179
185
  const projectInfo = await (0, exports.getProjectInfo)();
180
- const list = await Promise.all(['', 'user:'].map(specifier => // search text with multiple specifiers
181
- (0, misc_1.asyncGeneratorToArray)(apiGithubPaginated(`search/repositories?q=topic:hfs-plugin+${specifier}${encodeURI(text)}`))))
186
+ const searches = [encodeURI(text), ...text.split(' ').filter(Boolean).slice(0, 2).map(x => 'user:' + encodeURI(x))]; // first 2 words can be the author
187
+ const list = await Promise.all(searches.map(x => (0, misc_1.asyncGeneratorToArray)(apiGithubPaginated(`search/repositories?q=topic:hfs-plugin+${x}`))))
182
188
  .then(all => all.flat()); // make it a single array
183
189
  return new misc_1.AsapStream(list.map(async (it) => {
184
190
  var _a, _b;
package/src/listen.js CHANGED
@@ -283,14 +283,14 @@ async function getIps(external = true) {
283
283
  const ips = (0, misc_1.onlyTruthy)(Object.entries((0, os_1.networkInterfaces)()).flatMap(([name, nets]) => nets && !ignore.test(name) && nets.map(net => !net.internal && net.address)));
284
284
  const e = external && nat_1.defaultBaseUrl.externalIp;
285
285
  if (e && !ips.includes(e))
286
- ips.unshift(e);
286
+ ips.push(e);
287
287
  const noLinkLocal = ips.filter(x => !isLinkLocal(x));
288
- const ret = v4first(noLinkLocal.length ? noLinkLocal : ips);
289
- nat_1.defaultBaseUrl.localIp = ret[0] || '';
288
+ const ret = lodash_1.default.sortBy(noLinkLocal.length ? noLinkLocal : ips, [
289
+ x => x !== nat_1.defaultBaseUrl.localIp,
290
+ net_1.isIPv6 // false=IPV4 comes first
291
+ ]);
292
+ nat_1.defaultBaseUrl.localIp || (nat_1.defaultBaseUrl.localIp = ret[0] || '');
290
293
  return ret;
291
- function v4first(a) {
292
- return lodash_1.default.sortBy(a, net_1.isIPv6); // works because `false` comes first
293
- }
294
294
  }
295
295
  exports.getIps = getIps;
296
296
  async function getUrls() {
package/src/nat.js CHANGED
@@ -63,11 +63,10 @@ exports.getPublicIps = (0, debounceAsync_1.debounceAsync)(async () => {
63
63
  throw "no good";
64
64
  return validIps;
65
65
  }))));
66
- return lodash_1.default.uniq(ips.flat());
66
+ return exports.defaultBaseUrl.publicIps = lodash_1.default.uniq(ips.flat());
67
67
  }, 0, { retain: 10 * cross_1.MINUTE });
68
68
  exports.getNatInfo = (0, debounceAsync_1.debounceAsync)(async () => {
69
69
  var _a, _b, _c, _d;
70
- const gettingIps = (0, exports.getPublicIps)(); // don't wait, do it in parallel
71
70
  const res = await (0, cross_1.haveTimeout)(10000, exports.upnpClient.getGateway()).catch(() => null);
72
71
  const status = await (0, listen_1.getServerStatus)();
73
72
  const mappings = res && await (0, cross_1.haveTimeout)(5000, exports.upnpClient.getMappings()).catch(() => null);
@@ -78,12 +77,13 @@ exports.getNatInfo = (0, debounceAsync_1.debounceAsync)(async () => {
78
77
  const internalPort = ((_a = status === null || status === void 0 ? void 0 : status.https) === null || _a === void 0 ? void 0 : _a.listening) && status.https.port || ((_b = status === null || status === void 0 ? void 0 : status.http) === null || _b === void 0 ? void 0 : _b.listening) && status.http.port || undefined;
79
78
  const mapped = lodash_1.default.find(mappings, x => x.private.host === localIp && x.private.port === internalPort);
80
79
  const externalPort = mapped === null || mapped === void 0 ? void 0 : mapped.public.port;
80
+ if (localIp)
81
+ exports.defaultBaseUrl.localIp = localIp;
81
82
  exports.defaultBaseUrl.port = externalPort || internalPort || 0;
82
83
  return {
83
84
  upnp: Boolean(res),
84
85
  localIp,
85
86
  gatewayIp,
86
- publicIps: exports.defaultBaseUrl.publicIps = await gettingIps,
87
87
  externalIp: exports.defaultBaseUrl.externalIp,
88
88
  mapped,
89
89
  mapped80: lodash_1.default.find(mappings, x => x.private.host === localIp && x.private.port === 80 && x.public.port === 80),
@@ -92,6 +92,7 @@ exports.getNatInfo = (0, debounceAsync_1.debounceAsync)(async () => {
92
92
  proto: ((_c = status === null || status === void 0 ? void 0 : status.https) === null || _c === void 0 ? void 0 : _c.listening) ? 'https' : ((_d = status === null || status === void 0 ? void 0 : status.http) === null || _d === void 0 ? void 0 : _d.listening) ? 'http' : '',
93
93
  };
94
94
  });
95
+ (0, exports.getNatInfo)();
95
96
  function findGateway() {
96
97
  return new Promise((resolve, reject) => (0, child_process_1.exec)(const_1.IS_WINDOWS || const_1.IS_MAC ? 'netstat -rn' : 'route -n', (err, out) => {
97
98
  var _a;
package/src/plugins.js CHANGED
@@ -42,6 +42,7 @@ const fs_1 = require("fs");
42
42
  const connections_1 = require("./connections");
43
43
  const path_1 = require("path");
44
44
  const customHtml_1 = require("./customHtml");
45
+ const kvstorage_1 = require("@rejetto/kvstorage");
45
46
  exports.PATH = 'plugins';
46
47
  exports.DISABLING_SUFFIX = '-disabled';
47
48
  exports.STORAGE_FOLDER = 'storage';
@@ -389,6 +390,13 @@ function watchPlugin(id, path) {
389
390
  await initPlugin(pluginData, {
390
391
  srcDir: __dirname,
391
392
  storageDir,
393
+ async openDb(filename, options) {
394
+ if (!filename)
395
+ throw Error("missing filename");
396
+ const db = new kvstorage_1.KvStorage(options);
397
+ await db.open((0, path_1.join)(storageDir, filename));
398
+ return db;
399
+ },
392
400
  log(...args) {
393
401
  console.log('plugin', id + ':', ...args);
394
402
  },
package/src/roots.js CHANGED
@@ -1,10 +1,14 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.rootsMiddleware = exports.roots = void 0;
4
7
  const config_1 = require("./config");
5
8
  const misc_1 = require("./misc");
6
9
  const connections_1 = require("./connections");
7
10
  const listen_1 = require("./listen");
11
+ const lodash_1 = __importDefault(require("lodash"));
8
12
  exports.roots = (0, config_1.defineConfig)(misc_1.CFG.roots, {}, map => {
9
13
  const list = Object.keys(map);
10
14
  const matchers = list.map(hostMask => (0, misc_1.makeMatcher)(hostMask));
@@ -18,6 +22,7 @@ forceAddress.sub((v, { version }) => {
18
22
  });
19
23
  const rootsMiddleware = (ctx, next) => (() => {
20
24
  var _a;
25
+ ctx.state.originalPath = ctx.path;
21
26
  const root = (_a = exports.roots.compiled()) === null || _a === void 0 ? void 0 : _a(ctx.host);
22
27
  if (!ctx.state.skipFilters && forceAddress.get())
23
28
  if (root === undefined && !(0, misc_1.isLocalHost)(ctx) && ctx.host !== listen_1.baseUrl.compiled()) {
@@ -30,21 +35,26 @@ const rootsMiddleware = (ctx, next) => (() => {
30
35
  if (ctx.path.startsWith(misc_1.SPECIAL_URI)) { // special uris should be excluded...
31
36
  if (!ctx.path.startsWith(misc_1.API_URI))
32
37
  return; // ...unless it's an api
38
+ params = ctx.state.params || ctx.query; // for api we'll translate params
39
+ changeUriParams(v => (0, misc_1.removeStarting)(ctx.state.revProxyPath, v)); // removal must be done before adding the root
33
40
  let { referer } = ctx.headers;
34
41
  referer && (referer = new URL(referer).pathname);
35
42
  if (referer === null || referer === void 0 ? void 0 : referer.startsWith(ctx.state.revProxyPath + misc_1.ADMIN_URI))
36
43
  return; // exclude apis for admin-panel
37
- params = ctx.state.params || ctx.query; // for api we'll translate params
38
44
  }
39
- if (!params) {
40
- ctx.path = join(root, ctx.path);
45
+ if (lodash_1.default.isEmpty(exports.roots.get()))
46
+ return;
47
+ if (root === '' || root === '/')
41
48
  return;
49
+ changeUriParams(v => (0, misc_1.join)(root, v));
50
+ if (!params)
51
+ ctx.path = (0, misc_1.join)(root, ctx.path);
52
+ function changeUriParams(cb) {
53
+ if (!params)
54
+ return;
55
+ for (const [k, v] of Object.entries(params))
56
+ if (k.startsWith('uri'))
57
+ params[k] = Array.isArray(v) ? v.map(cb) : cb(v);
42
58
  }
43
- for (const [k, v] of Object.entries(params))
44
- if (k.startsWith('uri'))
45
- params[k] = Array.isArray(v) ? v.map(x => join(root, x)) : join(root, v);
46
59
  })() || next();
47
60
  exports.rootsMiddleware = rootsMiddleware;
48
- function join(a, b) {
49
- return a + (b && b[0] !== '/' ? '/' : '') + b;
50
- }
package/src/serveFile.js CHANGED
@@ -57,7 +57,7 @@ async function serveFile(ctx, source, mime, content) {
57
57
  return;
58
58
  const fn = (0, path_1.basename)(source);
59
59
  mime = mime !== null && mime !== void 0 ? mime : mimeCfg.compiled()(fn);
60
- if (mime === const_1.MIME_AUTO)
60
+ if (!mime || mime === const_1.MIME_AUTO)
61
61
  mime = mime_types_1.default.lookup(source) || '';
62
62
  if (mime)
63
63
  ctx.type = mime;
@@ -20,6 +20,7 @@ const serveGuiFiles_1 = require("./serveGuiFiles");
20
20
  const koa_mount_1 = __importDefault(require("koa-mount"));
21
21
  const listen_1 = require("./listen");
22
22
  const misc_1 = require("./misc");
23
+ const basicWeb_1 = require("./basicWeb");
23
24
  const serveFrontendFiles = (0, serveGuiFiles_1.serveGuiFiles)(process.env.FRONTEND_PROXY, cross_const_1.FRONTEND_URI);
24
25
  const serveFrontendPrefixed = (0, koa_mount_1.default)(cross_const_1.FRONTEND_URI.slice(0, -1), serveFrontendFiles);
25
26
  const serveAdminFiles = (0, serveGuiFiles_1.serveGuiFiles)(process.env.ADMIN_PROXY, cross_const_1.ADMIN_URI);
@@ -106,6 +107,8 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
106
107
  return serveFrontendFiles(ctx, next);
107
108
  }
108
109
  ctx.set({ server: `HFS ${const_1.VERSION} ${const_1.BUILD_TIMESTAMP}` });
110
+ if ((0, basicWeb_1.basicWeb)(ctx, node))
111
+ return;
109
112
  return get === 'zip' ? (0, zip_1.zipStreamFromFolder)(node, ctx)
110
113
  : get === 'list' ? sendFolderList(node, ctx)
111
114
  : serveFrontendFiles(ctx, next);
@@ -107,7 +107,7 @@ async function treatIndex(ctx, filesUri, body) {
107
107
  const timestamp = await getFaviconTimestamp();
108
108
  const lang = await (0, lang_1.getLangData)(ctx);
109
109
  return body
110
- .replace(/((?:src|href) *= *['"])\/?(?!([a-z]+:\/)?\/)/g, '$1' + ctx.state.revProxyPath + filesUri)
110
+ .replace(/((?:src|href) *= *['"])\/?(?!([a-z]+:\/)?\/)(?!\?)/g, '$1' + ctx.state.revProxyPath + filesUri)
111
111
  .replace(/<(\/)?(head|body)>/g, (all, isClose, name) => {
112
112
  const isHead = name === 'head';
113
113
  const isBody = !isHead;