hfs 0.47.3 → 0.48.0-alpha2

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 (41) hide show
  1. package/admin/assets/index-1c2b890b.css +1 -0
  2. package/admin/assets/index-344723f8.js +520 -0
  3. package/{frontend/assets/sha512-108e3b0a.js → admin/assets/sha512-136b5a7c.js} +1 -1
  4. package/admin/index.html +2 -2
  5. package/frontend/assets/index-05dfd82f.css +1 -0
  6. package/frontend/assets/{index-7eec0199.js → index-12411ff6.js} +15 -15
  7. package/{admin/assets/sha512-0935647a.js → frontend/assets/sha512-549e6c3a.js} +1 -1
  8. package/frontend/index.html +2 -2
  9. package/package.json +20 -13
  10. package/plugins/vhosting/plugin.js +15 -15
  11. package/src/adminApis.js +7 -4
  12. package/src/api.auth.js +0 -3
  13. package/src/api.file_list.js +8 -7
  14. package/src/api.lang.js +1 -1
  15. package/src/api.net.js +136 -0
  16. package/src/api.plugins.js +31 -36
  17. package/src/api.vfs.js +1 -1
  18. package/src/apiMiddleware.js +22 -20
  19. package/src/config.js +2 -16
  20. package/src/const.js +4 -2
  21. package/src/cross.js +221 -0
  22. package/src/customHtml.js +7 -22
  23. package/src/debounceAsync.js +12 -9
  24. package/src/frontEndApis.js +2 -4
  25. package/src/github.js +86 -40
  26. package/src/langs/embedded.js +2 -1
  27. package/src/langs/hfs-lang-de.json +131 -0
  28. package/src/langs/hfs-lang-it.json +1 -1
  29. package/src/listen.js +44 -37
  30. package/src/log.js +8 -5
  31. package/src/middlewares.js +1 -3
  32. package/src/misc.js +33 -137
  33. package/src/plugins.js +46 -26
  34. package/src/serveFile.js +1 -0
  35. package/src/update.js +1 -1
  36. package/src/upload.js +2 -1
  37. package/src/util-http.js +11 -8
  38. package/admin/assets/index-62247236.css +0 -1
  39. package/admin/assets/index-ca5ac85e.js +0 -518
  40. package/frontend/assets/index-0ea37f5f.css +0 -1
  41. package/src/util-generators.js +0 -31
@@ -0,0 +1,131 @@
1
+ {
2
+ "author": "kumpu",
3
+ "version": 1.0,
4
+ "hfs_version": "0.47.2",
5
+ "translate": {
6
+ "Select": "Auswählen",
7
+ "n_files": "{n,plural,one{# Datei} other{# Dateien}}",
8
+ "n_folders": "{n,plural,one{# Ordner} other{# Ordner}}",
9
+ "filter_count": "{n,plural, one{# gefiltert} other{# gefiltert}}",
10
+ "select_count": "{n,plural, one{# ausgewählt} other{# ausgewählt}}",
11
+ "filter_placeholder": "Filter...",
12
+ "Select some files": "Dateien auswählen",
13
+ "zip_checkboxes": "Nutzen Sie die Kästchen um Dateien auszuwählen, danach können sie die Zip-Funktion wieder benutzen",
14
+ "zip_tooltip_selected": "Ausgewählte Elemente als einzelne Zip-Datei herunterladen",
15
+ "zip_tooltip_whole": "Die ganze Liste (ungefiltert) als einzelne Zip-Datei herunterladen. Wenn Sie einige Elemente auswählen, werden nur diese herunterladen.",
16
+ "zip_confirm_search": "ALLE Ergebnisse dieser Suche als Zip-Datei herunterladen?",
17
+ "zip_confirm_folder": "GANZEN Ordner als Zip-Datei herunterladen?",
18
+ "select_tooltip": "Auswahl wird benutzt von \"Zip\" und \"Löschen\" (wenn verfügbar), aber Sie können die Liste auch filtern",
19
+ "delete_hint": "Clicken sie erst \"Auswählen\", um zu löschen",
20
+ "delete_confirm": "Lösche {n,plural, one{# Element} other{# Elemente}}?",
21
+ "delete_completed": "Löschen: {n} abgeschlossen",
22
+ "delete_failed": ", {n,plural, one{# fehlgeschlagen} other{# fehlgeschlagen}}",
23
+ "delete_select": "Wählen sie Elemente zum Löschen aus",
24
+ "Delete": "Löschen",
25
+ "Options": "Optionen",
26
+ "Search": "Suche",
27
+ "Zip": "Zip",
28
+ "search_msg": "Ordner und Unterordner durchsuchen",
29
+ "Searching": "Suche",
30
+ "Searched": "Gesucht",
31
+ "Clear search": "Ergebnisse löschen",
32
+ "Interrupted": "Abgebrochen",
33
+ "stopped_before": "Gestoppt bevor etwas gefunden wurde",
34
+ "empty_list": "Keine Treffer",
35
+ "filter_none": "Keine Treffer für Filter",
36
+ "Admin-panel": "Admin-Panel",
37
+ "Login": "Login",
38
+ "Username": "Benutzer",
39
+ "Password": "Passwort",
40
+ "login_untrusted": "Login abgebrochen: Serveridentität kann nicht vertraut werden",
41
+ "login_bad_credentials": "Ungültige Anmeldedaten",
42
+ "login_bad_cookies": "Cookies funktionieren nicht - Login gescheitert",
43
+ "User panel": "User-Panel",
44
+ "Change password": "Passwort ändern",
45
+ "enter_pass": "Neues Passwort eingeben",
46
+ "enter_pass2": "Neues Passwort erneut eingeben",
47
+ "pass2_mismatch": "Die Passwörter stimmen nicht überein. Vorgang abgebrochen.",
48
+ "password_changed": "Passwort geändert",
49
+ "Logout": "Logout",
50
+ "connection error": "Verbindungsfehler",
51
+ "Full timestamp:": "Ganzer Zeitstempel:",
52
+ "Search was interrupted": "Suche wurde abgebrochen",
53
+ "Stop list": "Suche abbrechen",
54
+ "upload_starting": "Ihr Download sollte jetzt starten",
55
+ "wrong_account": "Account {u} hat keinen Zugriff, versuchen Sie einen anderen",
56
+ "no_upload_here": "Keine Uploadberechtigung für den momentanen Ordner",
57
+ "Create folder": "Ordner erstellen",
58
+ "Pick files": "Dateien auswählen",
59
+ "Pick folder": "Ordner auswählen",
60
+ "send_files": "Uploade {n,plural,one{# Datei} other{# Dateien}}, {size}",
61
+ "Clear": "Upload abbrechen",
62
+ "failed_upload": "Konnte {name} nicht hochladen",
63
+ "confirm_resume": "Upload fortsetzen?",
64
+ "file too large": "Datei zu groß",
65
+ "Enter folder name": "Ordnername eingeben",
66
+ "Successfully created": "Erstellung erfolgreich",
67
+ "enter_folder": "Ordner öffnen",
68
+ "folder_exists": "Ein Ordner mit diesem Namen existiert bereits",
69
+ "Sort by:": "Sortieren nach: {by}",
70
+ "name": "Name",
71
+ "extension": "Dateityp",
72
+ "size": "Größe",
73
+ "time": "Datum",
74
+ "Invert order": "Umgekehrte Reihenfolge",
75
+ "Folders first": "Ordner zuerst",
76
+ "Numeric names": "Numerische Namen",
77
+ "theme:": "Theme:",
78
+ "auto": "Auto",
79
+ "light": "Hell",
80
+ "dark": "Dunkel",
81
+ "parent folder": "Übergeordneter Ordner",
82
+ "home": "Home",
83
+ "Continue": "Fortfahren",
84
+ "Confirm": "Bestätigen",
85
+ "Don't": "Abbrechen",
86
+ "Warning": "Warnung",
87
+ "Error": "Fehler",
88
+ "Info": "Info",
89
+ "Unauthorized": "Nicht autorisiert",
90
+ "Forbidden": "Verboten",
91
+ "Not found": "Nicht gefunden",
92
+ "Server error": "Server Fehler",
93
+ "Upload": "Upload",
94
+ "upload_concluded": "Upload abgeschlossen:",
95
+ "upload_finished": "{n} abgeschlossen ({size})",
96
+ "upload_errors": "{n} fehlgeschlagen",
97
+ "upload_file_rejected": "Einige Dateien wurden nicht akzeptiert",
98
+ "File menu": "Dateimenü",
99
+ "Folder menu": "Ordnermenü",
100
+ "Name": "Name",
101
+ "file_open": "Öffnen",
102
+ "Download": "Download",
103
+ "Missing permission": "Fehlende Berechtigung",
104
+ "Reload": "Neu laden",
105
+ "Get list": "Liste anzeigen",
106
+ "Skip existing files": "Überspringe existierende Dateien ",
107
+ "Size": "Größe",
108
+ "Timestamp": "Datum",
109
+ "Show": "Anzeigen",
110
+ "Loading failed": "Laden fehlgeschlagen",
111
+ "Rename": "Umbenennen",
112
+ "Tiles mode:": "Kachelmodus:",
113
+ "off": "Aus",
114
+ "Operation successful": "Operation erfolgreich",
115
+ "Uploader": "Uploader",
116
+ "Download counter": "Downloadzähler",
117
+ "Switch zoom mode": "Zoom Modus wechseln",
118
+ "Full screen": "Vollbild",
119
+ "File Show help": "Dateianzeige - Hilfe",
120
+ "showHelpMain": "Tastaturbefehle:",
121
+ "showHelp_←/→": "←/→",
122
+ "showHelp_↑/↓": "↑/↓",
123
+ "showHelp_space": "Leertaste",
124
+ "showHelp_←/→_body": "vorherige/nächste Datei",
125
+ "showHelp_↑/↓_body": "Hohe Bilder scrollen",
126
+ "showHelp_space_body": "Auswählen",
127
+ "showHelp_D_body": "Download",
128
+ "showHelp_Z_body": "Zoom Modus",
129
+ "showHelp_F_body": "Vollbildmodus"
130
+ }
131
+ }
@@ -28,7 +28,7 @@
28
28
  "Searching": "Cercando",
29
29
  "Searched": "Risultati ricerca",
30
30
  "Clear search": "Annulla ricerca",
31
- "Interrupted": "interrotto",
31
+ "Interrupted": "Interrotto",
32
32
  "stopped_before": "Ricerca interrotta prima di trovare risultati",
33
33
  "empty_list": "Non c'è niente qui",
34
34
  "filter_none": "Nessun elemento corrisponde al filtro impostato",
package/src/listen.js CHANGED
@@ -27,7 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  return (mod && mod.__esModule) ? mod : { "default": mod };
28
28
  };
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.getUrls = exports.getServerStatus = exports.httpsPortCfg = exports.openAdmin = exports.portCfg = exports.getHttpsWorkingPort = void 0;
30
+ exports.getUrls = exports.getIps = exports.getServerStatus = exports.httpsPortCfg = exports.openAdmin = exports.portCfg = exports.getHttpsWorkingPort = void 0;
31
31
  const http = __importStar(require("http"));
32
32
  const config_1 = require("./config");
33
33
  const index_1 = require("./index");
@@ -41,6 +41,8 @@ const const_1 = require("./const");
41
41
  const find_process_1 = __importDefault(require("find-process"));
42
42
  const adminApis_1 = require("./adminApis");
43
43
  const lodash_1 = __importDefault(require("lodash"));
44
+ const crypto_1 = require("crypto");
45
+ const api_net_1 = require("./api.net");
44
46
  let httpSrv;
45
47
  let httpsSrv;
46
48
  const openBrowserAtStart = (0, config_1.defineConfig)('open_browser_at_start', !const_1.DEV);
@@ -59,7 +61,7 @@ exports.portCfg.sub(async (port) => {
59
61
  if (!port)
60
62
  return;
61
63
  httpSrv.on('connection', connections_1.newConnection);
62
- printUrls(port, 'http');
64
+ printUrls(httpSrv.name);
63
65
  if (openBrowserAtStart.get() && !const_1.argv.updated)
64
66
  openAdmin();
65
67
  });
@@ -69,9 +71,9 @@ function openAdmin() {
69
71
  if (!a || typeof a === 'string')
70
72
  continue;
71
73
  const baseUrl = srv.name + '://localhost:' + a.port;
72
- (0, open_1.default)(baseUrl + const_1.ADMIN_URI, { wait: true }).catch(e => {
74
+ (0, open_1.default)(baseUrl + const_1.ADMIN_URI, { wait: true }).catch(async (e) => {
73
75
  console.debug(String(e));
74
- console.warn("cannot launch browser on this machine >PLEASE< open your browser and reach one of these (you may need a different address)", ...Object.values(getUrls()).flat().map(x => '\n - ' + x + const_1.ADMIN_URI));
76
+ console.warn("cannot launch browser on this machine >PLEASE< open your browser and reach one of these (you may need a different address)", ...Object.values(await getUrls()).flat().map(x => '\n - ' + x + const_1.ADMIN_URI));
75
77
  if (!(0, adminApis_1.anyAccountCanLoginAdmin)())
76
78
  console.log(`HINT: you can enter command: create-admin YOUR_PASSWORD`);
77
79
  });
@@ -81,19 +83,27 @@ function openAdmin() {
81
83
  }
82
84
  exports.openAdmin = openAdmin;
83
85
  const considerHttps = (0, misc_1.debounceAsync)(async () => {
84
- var _a, _b;
86
+ var _a, _b, _c;
85
87
  stopServer(httpsSrv).then();
86
88
  let port = exports.httpsPortCfg.get();
87
89
  try {
88
90
  while (!index_1.app)
89
91
  await (0, misc_1.wait)(100);
90
- httpsSrv = Object.assign(https.createServer(port < 0 ? {} : { key: httpsOptions.private_key, cert: httpsOptions.cert }, index_1.app.callback()), { name: 'https', error: undefined });
92
+ httpsSrv = Object.assign(https.createServer(port === PORT_DISABLED ? {} : { key: httpsOptions.private_key, cert: httpsOptions.cert }, index_1.app.callback()), { name: 'https' });
91
93
  if (port >= 0) {
94
+ const cert = new crypto_1.X509Certificate(httpsOptions.cert);
95
+ const cn = (_a = cert.subject.split('CN=')[1]) === null || _a === void 0 ? void 0 : _a.split('\n')[0];
96
+ if (cn)
97
+ console.log("certificate loaded for", cn);
98
+ const now = new Date();
99
+ httpsSrv.error = new Date(cert.validFrom) > now ? "certificate not valid yet"
100
+ : new Date(cert.validTo) < now ? "certificate expired"
101
+ : undefined;
92
102
  const namesForOutput = { cert: 'certificate', private_key: 'private key' };
93
- const missing = (_a = httpsNeeds.find(x => !x.get())) === null || _a === void 0 ? void 0 : _a.key();
103
+ const missing = (_b = httpsNeeds.find(x => !x.get())) === null || _b === void 0 ? void 0 : _b.key();
94
104
  if (missing)
95
105
  return httpsSrv.error = "missing " + namesForOutput[missing];
96
- const cantRead = (_b = httpsNeeds.find(x => !httpsOptions[x.key()])) === null || _b === void 0 ? void 0 : _b.key();
106
+ const cantRead = (_c = httpsNeeds.find(x => !httpsOptions[x.key()])) === null || _c === void 0 ? void 0 : _c.key();
97
107
  if (cantRead)
98
108
  return httpsSrv.error = "cannot read " + namesForOutput[cantRead];
99
109
  }
@@ -107,7 +117,7 @@ const considerHttps = (0, misc_1.debounceAsync)(async () => {
107
117
  if (!port)
108
118
  return;
109
119
  httpsSrv.on('connection', connections_1.newConnection);
110
- printUrls(port, 'https');
120
+ printUrls(httpsSrv.name);
111
121
  });
112
122
  const cert = (0, config_1.defineConfig)('cert', '');
113
123
  const privateKey = (0, config_1.defineConfig)('private_key', '');
@@ -130,14 +140,15 @@ for (const cfg of httpsNeeds) {
130
140
  await considerHttps();
131
141
  });
132
142
  }
133
- exports.httpsPortCfg = (0, config_1.defineConfig)('https_port', -1);
143
+ const PORT_DISABLED = -1;
144
+ exports.httpsPortCfg = (0, config_1.defineConfig)('https_port', PORT_DISABLED);
134
145
  exports.httpsPortCfg.sub(considerHttps);
135
146
  function startServer(srv, { port, host }) {
136
147
  return new Promise(async (resolve) => {
137
148
  if (!srv)
138
149
  return 0;
139
150
  try {
140
- if (port < 0 || !host && !await testIpV4()) // !host means ipV4+6, and if v4 port alone is busy we won't be notified of the failure, so we'll first test it on its own
151
+ if (port === PORT_DISABLED || !host && !await testIpV4()) // !host means ipV4+6, and if v4 port alone is busy we won't be notified of the failure, so we'll first test it on its own
141
152
  return resolve(0);
142
153
  // from a few tests, this seems enough to support the expect-100 http/1.1 mechanism, at least with curl -T, not used by chrome|firefox anyway
143
154
  srv.on('checkContinue', (req, res) => srv.emit('request', req, res));
@@ -216,40 +227,36 @@ async function getServerStatus() {
216
227
  }
217
228
  exports.getServerStatus = getServerStatus;
218
229
  const ignore = /^(lo|.*loopback.*|virtualbox.*|.*\(wsl\).*|llw\d|awdl\d|utun\d|anpi\d)$/i; // avoid giving too much information
219
- function getUrls() {
230
+ async function getIps() {
231
+ const ips = (0, misc_1.onlyTruthy)(Object.entries((0, os_1.networkInterfaces)()).map(([name, nets]) => nets && !ignore.test(name)
232
+ && v4first((0, misc_1.onlyTruthy)(nets.map(net => !net.internal && net.address)))[0] // for each interface we consider only 1 address
233
+ )).flat();
234
+ const e = await api_net_1.externalIp;
235
+ if (e)
236
+ ips.unshift(e);
237
+ return v4first(ips)
238
+ .filter((x, i, a) => a.length > 1 || !x.startsWith('169.254')); // 169.254 = dhcp failure on the interface, but keep it if it's our only one
239
+ function v4first(a) {
240
+ return lodash_1.default.sortBy(a, x => x.includes(':'));
241
+ }
242
+ }
243
+ exports.getIps = getIps;
244
+ async function getUrls() {
245
+ const ips = (await getIps()).map(ip => ip.includes(':') ? '[' + ip + ']' : ip);
220
246
  return Object.fromEntries((0, misc_1.onlyTruthy)([httpSrv, httpsSrv].map(srv => {
221
247
  var _a;
222
248
  if (!(srv === null || srv === void 0 ? void 0 : srv.listening))
223
249
  return false;
224
250
  const port = (_a = srv === null || srv === void 0 ? void 0 : srv.address()) === null || _a === void 0 ? void 0 : _a.port;
225
251
  const appendPort = port === (srv.name === 'https' ? 443 : 80) ? '' : ':' + port;
226
- const urls = (0, misc_1.onlyTruthy)(Object.entries((0, os_1.networkInterfaces)()).map(([name, nets]) => nets && !ignore.test(name) && nets.map(net => {
227
- if (net.internal)
228
- return;
229
- let { address } = net;
230
- if (address.includes(':'))
231
- address = '[' + address + ']';
232
- return srv.name + '://' + address + appendPort;
233
- })).flat());
252
+ const urls = ips.map(ip => `${srv.name}://${ip}${appendPort}`);
234
253
  return urls.length && [srv.name, urls];
235
254
  })));
236
255
  }
237
256
  exports.getUrls = getUrls;
238
- function printUrls(port, proto) {
239
- if (!port)
240
- return;
241
- for (const [name, nets] of Object.entries((0, os_1.networkInterfaces)())) {
242
- if (!nets || ignore.test(name))
243
- continue;
244
- lodash_1.default.remove(nets, 'internal');
245
- const first = nets[0];
246
- if (!first)
247
- continue;
248
- const best = lodash_1.default.find(nets, { family: 'IPv4' }) || first;
249
- const appendPort = port === (proto === 'https' ? 443 : 80) ? '' : ':' + port;
250
- let { address } = best;
251
- if (address.includes(':'))
252
- address = '[' + address + ']';
253
- console.log('network', name, proto + '://' + address + appendPort);
254
- }
257
+ function printUrls(srvName) {
258
+ getUrls().then(urls => {
259
+ for (const url of urls[srvName])
260
+ console.log('serving on', url);
261
+ });
255
262
  }
package/src/log.js CHANGED
@@ -89,7 +89,7 @@ const logMw = async (ctx, next) => {
89
89
  // don't await, as we don't want to hold the middlewares chain
90
90
  ctx.state.completed = Promise.race([(0, stream_1.once)(ctx.res, 'finish'), (0, stream_1.once)(ctx.res, 'close')]);
91
91
  ctx.state.completed.then(() => {
92
- var _a, _b, _c, _d, _e;
92
+ var _a, _b, _c, _d;
93
93
  if (ctx.state.dont_log)
94
94
  return;
95
95
  if (dontLogNet.compiled()(ctx.ip))
@@ -120,16 +120,19 @@ const logMw = async (ctx, next) => {
120
120
  return;
121
121
  }
122
122
  }
123
- const format = '%s - %s [%s] "%s %s HTTP/%s" %d %s\n'; // Apache's Common Log Format
123
+ const format = '%s - %s [%s] "%s %s HTTP/%s" %d %s %s\n'; // Apache's Common Log Format
124
124
  const a = now.toString().split(' ');
125
125
  const date = a[2] + '/' + a[1] + '/' + a[3] + ':' + a[4] + ' ' + ((_b = a[5]) === null || _b === void 0 ? void 0 : _b.slice(3));
126
126
  const user = (0, perm_1.getCurrentUsername)(ctx);
127
127
  const length = (_c = ctx.state.length) !== null && _c !== void 0 ? _c : ctx.length;
128
- const uri = (_d = ctx.originalUrl) === null || _d === void 0 ? void 0 : _d.replace(/&?csrf=[^&]+/, ''); // temporary workaround. To avoid csrf in url we need to stop using EventSource.
129
- events_1.default.emit(logger.name, Object.assign(lodash_1.default.pick(ctx, ['ip', 'method', 'status']), { length, user, ts: now, uri }));
128
+ const uri = ctx.originalUrl;
129
+ const extra = ctx.state.includesLastByte && ctx.vfsNode && { dl: 1 }
130
+ || ctx.state.uploadPath && { ul: ctx.state.uploadPath, size: ctx.state.uploadSize }
131
+ || undefined;
132
+ events_1.default.emit(logger.name, Object.assign(lodash_1.default.pick(ctx, ['ip', 'method', 'status']), { length, user, ts: now, uri, extra }));
130
133
  debounce(() => // once in a while we check if the file is still good (not deleted, etc), or we'll reopen it
131
134
  (0, promises_1.stat)(logger.path).catch(() => logger.reopen())); // async = smoother but we may lose some entries
132
- stream.write(util.format(format, ctx.ip, user || '-', date, ctx.method, uri, ctx.req.httpVersion, ctx.status, (_e = length === null || length === void 0 ? void 0 : length.toString()) !== null && _e !== void 0 ? _e : '-'));
135
+ stream.write(util.format(format, ctx.ip, user || '-', date, ctx.method, uri, ctx.req.httpVersion, ctx.status, (_d = length === null || length === void 0 ? void 0 : length.toString()) !== null && _d !== void 0 ? _d : '-', extra ? JSON.stringify(JSON.stringify(extra)) : ''));
133
136
  });
134
137
  };
135
138
  exports.logMw = logMw;
@@ -248,11 +248,9 @@ async function srpCheck(username, password) {
248
248
  const clientRes2 = await clientRes1.step2(BigInt(salt), BigInt(pubKey));
249
249
  return await step1.step2(clientRes2.A, clientRes2.M1).then(() => true, () => false);
250
250
  }
251
- // unify get/post parameters, with JSON decoding to not be limited to strings
252
251
  const paramsDecoder = async (ctx, next) => {
253
252
  ctx.params = ctx.method === 'POST' && ctx.originalUrl.startsWith(const_1.API_URI)
254
- ? (0, misc_1.tryJson)(await (0, misc_1.stream2string)(ctx.req))
255
- : (0, misc_1.newObj)(ctx.query, x => Array.isArray(x) ? x : (0, misc_1.tryJson)(x));
253
+ && ((0, misc_1.tryJson)(await (0, misc_1.stream2string)(ctx.req)) || {});
256
254
  await next();
257
255
  };
258
256
  exports.paramsDecoder = paramsDecoder;
package/src/misc.js CHANGED
@@ -18,92 +18,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
18
18
  return (mod && mod.__esModule) ? mod : { "default": mod };
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.throw_ = exports.try_ = exports.stream2string = exports.tryJson = exports.same = exports.matches = exports.makeMatcher = exports.makeNetMatcher = exports.isLocalHost = exports.with_ = exports.hasProp = exports.typedEntries = exports.typedKeys = exports.objRenameKey = exports.onOff = exports.pendingPromise = exports.onlyTruthy = exports.truthy = exports.pattern2filter = exports.onFirstEvent = exports.onProcessExit = exports.randomId = exports.getOrSet = exports.wantArray = exports.waitFor = exports.wait = exports.newObj = exports.setHidden = exports.prefix = exports.removeStarting = exports.enforceFinal = exports.debounceAsync = void 0;
21
+ exports.asyncGeneratorToReadable = exports.stream2string = exports.same = exports.matches = exports.makeMatcher = exports.makeNetMatcher = exports.isLocalHost = exports.onOff = exports.pattern2filter = exports.onFirstEvent = exports.onProcessExit = exports.debounceAsync = void 0;
22
22
  const path_1 = require("path");
23
23
  const lodash_1 = __importDefault(require("lodash"));
24
24
  const assert_1 = __importDefault(require("assert"));
25
25
  __exportStar(require("./util-http"), exports);
26
- __exportStar(require("./util-generators"), exports);
27
26
  __exportStar(require("./util-files"), exports);
27
+ __exportStar(require("./cross"), exports);
28
+ const stream_1 = require("stream");
29
+ const micromatch_1 = require("micromatch");
30
+ const node_net_1 = require("node:net");
28
31
  const debounceAsync_1 = __importDefault(require("./debounceAsync"));
29
32
  exports.debounceAsync = debounceAsync_1.default;
30
- const micromatch_1 = require("micromatch");
31
- const cidr_tools_1 = __importDefault(require("cidr-tools"));
32
- function enforceFinal(sub, s) {
33
- return s.endsWith(sub) ? s : s + sub;
34
- }
35
- exports.enforceFinal = enforceFinal;
36
- function removeStarting(sub, s) {
37
- return s.startsWith(sub) ? s.slice(sub.length) : s;
38
- }
39
- exports.removeStarting = removeStarting;
40
- function prefix(pre, v, post = '') {
41
- return v ? pre + v + post : '';
42
- }
43
- exports.prefix = prefix;
44
- function setHidden(dest, src) {
45
- return Object.defineProperties(dest, newObj(src, value => ({
46
- enumerable: false,
47
- writable: true,
48
- value,
49
- })));
50
- }
51
- exports.setHidden = setHidden;
52
- function newObj(src, returnNewValue, recur = false) {
53
- if (!src)
54
- return {};
55
- const pairs = Object.entries(src).map(([k, v]) => {
56
- if (typeof k === 'symbol')
57
- return;
58
- let _k = k;
59
- const curDepth = typeof recur === 'number' ? recur : 0;
60
- let newV = returnNewValue(v, k, (newK) => {
61
- _k = newK;
62
- return true; // for convenient expression concatenation
63
- }, curDepth);
64
- if ((recur !== false || returnNewValue.length === 4) // if callback is using depth parameter, then it wants recursion
65
- && lodash_1.default.isPlainObject(newV)) // is it recurrable?
66
- newV = newObj(newV, returnNewValue, curDepth + 1);
67
- return _k !== undefined && [_k, newV];
68
- });
69
- return Object.fromEntries(onlyTruthy(pairs));
70
- }
71
- exports.newObj = newObj;
72
- function wait(ms) {
73
- return new Promise(res => setTimeout(res, ms));
74
- }
75
- exports.wait = wait;
76
- async function waitFor(cb, { interval = 200, timeout = Infinity } = {}) {
77
- const started = Date.now();
78
- while (1) {
79
- const res = await cb();
80
- if (res)
81
- return res;
82
- if (Date.now() - started >= timeout)
83
- return;
84
- await wait(interval);
85
- }
86
- }
87
- exports.waitFor = waitFor;
88
- function wantArray(x) {
89
- return x == null ? [] : Array.isArray(x) ? x : [x];
90
- }
91
- exports.wantArray = wantArray;
92
- function getOrSet(o, k, creator) {
93
- return k in o ? o[k]
94
- : (o[k] = creator());
95
- }
96
- exports.getOrSet = getOrSet;
97
- // 10 chars is 51+bits, 8 is 41+bits
98
- function randomId(len = 10) {
99
- if (len > 10)
100
- return randomId(10) + randomId(len - 10);
101
- return Math.random()
102
- .toString(36)
103
- .substring(2, 2 + len)
104
- .replace(/l/g, 'L'); // avoid confusion reading l1
105
- }
106
- exports.randomId = randomId;
107
33
  const cbs = new Set();
108
34
  function onProcessExit(cb) {
109
35
  cbs.add(cb);
@@ -127,20 +53,6 @@ function pattern2filter(pattern) {
127
53
  return (s) => !s || !pattern || re.test((0, path_1.basename)(s));
128
54
  }
129
55
  exports.pattern2filter = pattern2filter;
130
- function truthy(value) {
131
- return Boolean(value);
132
- }
133
- exports.truthy = truthy;
134
- function onlyTruthy(arr) {
135
- return arr.filter(truthy);
136
- }
137
- exports.onlyTruthy = onlyTruthy;
138
- function pendingPromise() {
139
- let takeOut;
140
- const ret = new Promise((resolve, reject) => takeOut = { resolve, reject });
141
- return Object.assign(ret, takeOut);
142
- }
143
- exports.pendingPromise = pendingPromise;
144
56
  // install multiple handlers and returns a handy 'uninstall' function which requires no parameter. Pass a map {event:handler}
145
57
  function onOff(em, events) {
146
58
  events = { ...events }; // avoid later modifications, as we need this later for uninstallation
@@ -154,30 +66,6 @@ function onOff(em, events) {
154
66
  };
155
67
  }
156
68
  exports.onOff = onOff;
157
- function objRenameKey(o, from, to) {
158
- if (!o || !o.hasOwnProperty(from) || from === to)
159
- return;
160
- o[to] = o[from];
161
- delete o[from];
162
- return true;
163
- }
164
- exports.objRenameKey = objRenameKey;
165
- function typedKeys(o) {
166
- return Object.keys(o);
167
- }
168
- exports.typedKeys = typedKeys;
169
- function typedEntries(o) {
170
- return Object.entries(o);
171
- }
172
- exports.typedEntries = typedEntries;
173
- function hasProp(obj, key) {
174
- return key in obj;
175
- }
176
- exports.hasProp = hasProp;
177
- function with_(par, cb) {
178
- return cb(par);
179
- }
180
- exports.with_ = with_;
181
69
  function isLocalHost(c) {
182
70
  const ip = c.socket.remoteAddress; // don't use Context.ip as it is subject to proxied ips, and that's no use for localhost detection
183
71
  return ip && (ip === '::1' || ip.endsWith('127.0.0.1'));
@@ -193,9 +81,27 @@ function makeNetMatcher(mask, emptyMaskReturns = false) {
193
81
  const neg = ((_a = all[0]) === null || _a === void 0 ? void 0 : _a[0]) === '!';
194
82
  if (neg)
195
83
  all[0] = all[0].slice(1);
196
- return (ip) => neg !== all.some(x => cidr_tools_1.default.contains(x, ip));
84
+ const bl = new node_net_1.BlockList();
85
+ for (const x of all) {
86
+ const m = /^([.:\d]+)(?:\/(\d+)|-(.+)|)$/.exec(x);
87
+ if (!m) {
88
+ console.warn("error in network mask", x);
89
+ continue;
90
+ }
91
+ const address = parseAddress(m[1]);
92
+ if (m[2])
93
+ bl.addSubnet(address, Number(m[2]));
94
+ else if (m[3])
95
+ bl.addRange(address, parseAddress(m[2]));
96
+ else
97
+ bl.addAddress(address);
98
+ }
99
+ return (ip) => neg !== bl.check(ip);
197
100
  }
198
101
  exports.makeNetMatcher = makeNetMatcher;
102
+ function parseAddress(s) {
103
+ return new node_net_1.SocketAddress({ address: s, family: s.includes(':') ? 'ipv6' : 'ipv4' });
104
+ }
199
105
  function makeMatcher(mask, emptyMaskReturns = false) {
200
106
  return mask ? (0, micromatch_1.matcher)(mask.replace(/^(!)?/, '$1(') + ')') // adding () will allow us to use the pipe at root level
201
107
  : () => emptyMaskReturns;
@@ -215,13 +121,6 @@ function same(a, b) {
215
121
  }
216
122
  }
217
123
  exports.same = same;
218
- function tryJson(s) {
219
- try {
220
- return s && JSON.parse(s);
221
- }
222
- catch (_a) { }
223
- }
224
- exports.tryJson = tryJson;
225
124
  async function stream2string(stream) {
226
125
  return new Promise((resolve, reject) => {
227
126
  let data = '';
@@ -238,16 +137,13 @@ async function stream2string(stream) {
238
137
  });
239
138
  }
240
139
  exports.stream2string = stream2string;
241
- function try_(cb, onException) {
242
- try {
243
- return cb();
244
- }
245
- catch (e) {
246
- return onException === null || onException === void 0 ? void 0 : onException(e);
247
- }
248
- }
249
- exports.try_ = try_;
250
- function throw_(err) {
251
- throw err;
140
+ function asyncGeneratorToReadable(generator) {
141
+ const iterator = generator[Symbol.asyncIterator]();
142
+ return new stream_1.Readable({
143
+ objectMode: true,
144
+ read() {
145
+ iterator.next().then(it => this.push(it.done ? null : it.value));
146
+ }
147
+ });
252
148
  }
253
- exports.throw_ = throw_;
149
+ exports.asyncGeneratorToReadable = asyncGeneratorToReadable;