@electron-memory/monitor 0.2.2 → 0.2.3

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.
package/dist/index.js CHANGED
@@ -1114,6 +1114,7 @@ var path3 = __toESM(require("path"));
1114
1114
  var import_electron2 = require("electron");
1115
1115
  var import_promises = require("fs/promises");
1116
1116
  var path2 = __toESM(require("path"));
1117
+ var import_node_url = require("url");
1117
1118
  var SCHEME = "emm-dashboard";
1118
1119
  var privilegedRegistered = false;
1119
1120
  var handlerRegistered = false;
@@ -1148,6 +1149,48 @@ function isPathInsideRoot(filePath, root) {
1148
1149
  }
1149
1150
  return true;
1150
1151
  }
1152
+ function urlToUiRelativePath(requestUrl) {
1153
+ let u;
1154
+ try {
1155
+ u = new URL(requestUrl);
1156
+ } catch {
1157
+ return "";
1158
+ }
1159
+ let p = "";
1160
+ try {
1161
+ p = decodeURIComponent(u.pathname || "");
1162
+ } catch {
1163
+ p = u.pathname || "";
1164
+ }
1165
+ p = p.replace(/^\/+/, "");
1166
+ const host = (u.hostname || "").toLowerCase();
1167
+ if (p.includes("..")) {
1168
+ return "";
1169
+ }
1170
+ if (host === "electron" || host === "") {
1171
+ return p || "index.html";
1172
+ }
1173
+ if (p) {
1174
+ return `${host}/${p}`.replace(/\\/g, "/");
1175
+ }
1176
+ if (host.includes(".")) {
1177
+ return host;
1178
+ }
1179
+ return "index.html";
1180
+ }
1181
+ function bufferToResponseBody(buf) {
1182
+ return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
1183
+ }
1184
+ function looksLikeHtml(buf) {
1185
+ let i = 0;
1186
+ if (buf.length >= 3 && buf[0] === 239 && buf[1] === 187 && buf[2] === 191) {
1187
+ i = 3;
1188
+ }
1189
+ while (i < buf.length && (buf[i] === 32 || buf[i] === 9 || buf[i] === 10 || buf[i] === 13)) {
1190
+ i += 1;
1191
+ }
1192
+ return i < buf.length && buf[i] === 60;
1193
+ }
1151
1194
  function corsHeaders() {
1152
1195
  return {
1153
1196
  "Access-Control-Allow-Origin": "*",
@@ -1189,24 +1232,40 @@ function ensureDashboardProtocolHandler(uiRoot) {
1189
1232
  return new Response(null, { status: 204, headers: corsHeaders() });
1190
1233
  }
1191
1234
  try {
1192
- let pathname;
1193
- try {
1194
- pathname = decodeURIComponent(new URL(request.url).pathname);
1195
- } catch {
1196
- return new Response("Bad URL", { status: 400, headers: corsHeaders() });
1235
+ const rel = urlToUiRelativePath(request.url);
1236
+ if (!rel || rel.includes("..")) {
1237
+ return new Response("Bad path", { status: 400, headers: corsHeaders() });
1197
1238
  }
1198
- let rel = pathname.replace(/^\/+/, "");
1199
- if (!rel) {
1200
- rel = "index.html";
1201
- }
1202
- const filePath = path2.resolve(path2.join(base, rel));
1239
+ const filePath = path2.resolve(path2.join(base, ...rel.split("/")));
1203
1240
  if (!isPathInsideRoot(filePath, base)) {
1204
1241
  return new Response("Forbidden", { status: 403, headers: corsHeaders() });
1205
1242
  }
1206
- const body = await (0, import_promises.readFile)(filePath);
1243
+ const fileUrl = (0, import_node_url.pathToFileURL)(filePath).href;
1244
+ let upstream;
1245
+ try {
1246
+ upstream = await import_electron2.net.fetch(fileUrl);
1247
+ } catch {
1248
+ upstream = new Response(null, { status: 599 });
1249
+ }
1250
+ let buf;
1251
+ if (!upstream.ok) {
1252
+ buf = await (0, import_promises.readFile)(filePath);
1253
+ } else {
1254
+ const ab = await upstream.arrayBuffer();
1255
+ buf = Buffer.from(ab);
1256
+ }
1207
1257
  const ext = path2.extname(filePath).toLowerCase();
1258
+ if (ext === ".html" && !looksLikeHtml(buf)) {
1259
+ console.error(
1260
+ "[@electron-memory/monitor] emm-dashboard: not HTML at",
1261
+ filePath,
1262
+ "url=",
1263
+ request.url
1264
+ );
1265
+ return new Response("Invalid dashboard HTML", { status: 500, headers: corsHeaders() });
1266
+ }
1208
1267
  const mime = MIME_BY_EXT[ext] || "application/octet-stream";
1209
- return new Response(body, {
1268
+ return new Response(bufferToResponseBody(buf), {
1210
1269
  status: 200,
1211
1270
  headers: {
1212
1271
  "Content-Type": mime,
@@ -1216,6 +1275,7 @@ function ensureDashboardProtocolHandler(uiRoot) {
1216
1275
  });
1217
1276
  } catch (err) {
1218
1277
  const msg = err instanceof Error ? err.message : String(err);
1278
+ console.error("[@electron-memory/monitor] emm-dashboard:", request.url, err);
1219
1279
  return new Response(msg, { status: 404, headers: corsHeaders() });
1220
1280
  }
1221
1281
  });