@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 +72 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +73 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1073,9 +1073,10 @@ import { BrowserWindow as BrowserWindow2 } from "electron";
|
|
|
1073
1073
|
import * as path3 from "path";
|
|
1074
1074
|
|
|
1075
1075
|
// src/core/dashboard-protocol.ts
|
|
1076
|
-
import { app as app2, protocol } from "electron";
|
|
1076
|
+
import { app as app2, net, protocol } from "electron";
|
|
1077
1077
|
import { readFile } from "fs/promises";
|
|
1078
1078
|
import * as path2 from "path";
|
|
1079
|
+
import { pathToFileURL } from "url";
|
|
1079
1080
|
var SCHEME = "emm-dashboard";
|
|
1080
1081
|
var privilegedRegistered = false;
|
|
1081
1082
|
var handlerRegistered = false;
|
|
@@ -1110,6 +1111,48 @@ function isPathInsideRoot(filePath, root) {
|
|
|
1110
1111
|
}
|
|
1111
1112
|
return true;
|
|
1112
1113
|
}
|
|
1114
|
+
function urlToUiRelativePath(requestUrl) {
|
|
1115
|
+
let u;
|
|
1116
|
+
try {
|
|
1117
|
+
u = new URL(requestUrl);
|
|
1118
|
+
} catch {
|
|
1119
|
+
return "";
|
|
1120
|
+
}
|
|
1121
|
+
let p = "";
|
|
1122
|
+
try {
|
|
1123
|
+
p = decodeURIComponent(u.pathname || "");
|
|
1124
|
+
} catch {
|
|
1125
|
+
p = u.pathname || "";
|
|
1126
|
+
}
|
|
1127
|
+
p = p.replace(/^\/+/, "");
|
|
1128
|
+
const host = (u.hostname || "").toLowerCase();
|
|
1129
|
+
if (p.includes("..")) {
|
|
1130
|
+
return "";
|
|
1131
|
+
}
|
|
1132
|
+
if (host === "electron" || host === "") {
|
|
1133
|
+
return p || "index.html";
|
|
1134
|
+
}
|
|
1135
|
+
if (p) {
|
|
1136
|
+
return `${host}/${p}`.replace(/\\/g, "/");
|
|
1137
|
+
}
|
|
1138
|
+
if (host.includes(".")) {
|
|
1139
|
+
return host;
|
|
1140
|
+
}
|
|
1141
|
+
return "index.html";
|
|
1142
|
+
}
|
|
1143
|
+
function bufferToResponseBody(buf) {
|
|
1144
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
1145
|
+
}
|
|
1146
|
+
function looksLikeHtml(buf) {
|
|
1147
|
+
let i = 0;
|
|
1148
|
+
if (buf.length >= 3 && buf[0] === 239 && buf[1] === 187 && buf[2] === 191) {
|
|
1149
|
+
i = 3;
|
|
1150
|
+
}
|
|
1151
|
+
while (i < buf.length && (buf[i] === 32 || buf[i] === 9 || buf[i] === 10 || buf[i] === 13)) {
|
|
1152
|
+
i += 1;
|
|
1153
|
+
}
|
|
1154
|
+
return i < buf.length && buf[i] === 60;
|
|
1155
|
+
}
|
|
1113
1156
|
function corsHeaders() {
|
|
1114
1157
|
return {
|
|
1115
1158
|
"Access-Control-Allow-Origin": "*",
|
|
@@ -1151,24 +1194,40 @@ function ensureDashboardProtocolHandler(uiRoot) {
|
|
|
1151
1194
|
return new Response(null, { status: 204, headers: corsHeaders() });
|
|
1152
1195
|
}
|
|
1153
1196
|
try {
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
} catch {
|
|
1158
|
-
return new Response("Bad URL", { status: 400, headers: corsHeaders() });
|
|
1197
|
+
const rel = urlToUiRelativePath(request.url);
|
|
1198
|
+
if (!rel || rel.includes("..")) {
|
|
1199
|
+
return new Response("Bad path", { status: 400, headers: corsHeaders() });
|
|
1159
1200
|
}
|
|
1160
|
-
|
|
1161
|
-
if (!rel) {
|
|
1162
|
-
rel = "index.html";
|
|
1163
|
-
}
|
|
1164
|
-
const filePath = path2.resolve(path2.join(base, rel));
|
|
1201
|
+
const filePath = path2.resolve(path2.join(base, ...rel.split("/")));
|
|
1165
1202
|
if (!isPathInsideRoot(filePath, base)) {
|
|
1166
1203
|
return new Response("Forbidden", { status: 403, headers: corsHeaders() });
|
|
1167
1204
|
}
|
|
1168
|
-
const
|
|
1205
|
+
const fileUrl = pathToFileURL(filePath).href;
|
|
1206
|
+
let upstream;
|
|
1207
|
+
try {
|
|
1208
|
+
upstream = await net.fetch(fileUrl);
|
|
1209
|
+
} catch {
|
|
1210
|
+
upstream = new Response(null, { status: 599 });
|
|
1211
|
+
}
|
|
1212
|
+
let buf;
|
|
1213
|
+
if (!upstream.ok) {
|
|
1214
|
+
buf = await readFile(filePath);
|
|
1215
|
+
} else {
|
|
1216
|
+
const ab = await upstream.arrayBuffer();
|
|
1217
|
+
buf = Buffer.from(ab);
|
|
1218
|
+
}
|
|
1169
1219
|
const ext = path2.extname(filePath).toLowerCase();
|
|
1220
|
+
if (ext === ".html" && !looksLikeHtml(buf)) {
|
|
1221
|
+
console.error(
|
|
1222
|
+
"[@electron-memory/monitor] emm-dashboard: not HTML at",
|
|
1223
|
+
filePath,
|
|
1224
|
+
"url=",
|
|
1225
|
+
request.url
|
|
1226
|
+
);
|
|
1227
|
+
return new Response("Invalid dashboard HTML", { status: 500, headers: corsHeaders() });
|
|
1228
|
+
}
|
|
1170
1229
|
const mime = MIME_BY_EXT[ext] || "application/octet-stream";
|
|
1171
|
-
return new Response(
|
|
1230
|
+
return new Response(bufferToResponseBody(buf), {
|
|
1172
1231
|
status: 200,
|
|
1173
1232
|
headers: {
|
|
1174
1233
|
"Content-Type": mime,
|
|
@@ -1178,6 +1237,7 @@ function ensureDashboardProtocolHandler(uiRoot) {
|
|
|
1178
1237
|
});
|
|
1179
1238
|
} catch (err) {
|
|
1180
1239
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1240
|
+
console.error("[@electron-memory/monitor] emm-dashboard:", request.url, err);
|
|
1181
1241
|
return new Response(msg, { status: 404, headers: corsHeaders() });
|
|
1182
1242
|
}
|
|
1183
1243
|
});
|