autotel-devtools 8.0.0 → 8.1.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.
@@ -1,4 +1,4 @@
1
1
  import '@opentelemetry/sdk-trace-base';
2
2
  import '@opentelemetry/core';
3
- export { a as DevtoolsSpanExporter } from '../exporter-DjLkU621.cjs';
3
+ export { a as DevtoolsSpanExporter } from '../exporter-De6p4iAD.cjs';
4
4
  import 'node:http';
@@ -1,4 +1,4 @@
1
1
  import '@opentelemetry/sdk-trace-base';
2
2
  import '@opentelemetry/core';
3
- export { a as DevtoolsSpanExporter } from '../exporter-DjLkU621.js';
3
+ export { a as DevtoolsSpanExporter } from '../exporter-De6p4iAD.js';
4
4
  import 'node:http';
@@ -363,6 +363,40 @@ function applyTelemetryLimits(data, limits) {
363
363
  };
364
364
  }
365
365
 
366
+ // src/server/origin-guard.ts
367
+ var LOOPBACK_IPV6 = /* @__PURE__ */ new Set(["::1", "0:0:0:0:0:0:0:1"]);
368
+ function isLoopbackHostname(hostname) {
369
+ const h = hostname.toLowerCase().replace(/^\[|\]$/g, "");
370
+ return h === "localhost" || /^127\./.test(h) || LOOPBACK_IPV6.has(h);
371
+ }
372
+ function hostnameFromHostHeader(host) {
373
+ const h = host.trim();
374
+ if (h.startsWith("[")) {
375
+ const end = h.indexOf("]");
376
+ return end > 0 ? h.slice(1, end) : h;
377
+ }
378
+ const colon = h.indexOf(":");
379
+ return colon === -1 ? h : h.slice(0, colon);
380
+ }
381
+ function hostHeaderIsLoopback(host) {
382
+ return isLoopbackHostname(hostnameFromHostHeader(host));
383
+ }
384
+ function originIsLoopback(origin) {
385
+ try {
386
+ return isLoopbackHostname(new URL(origin).hostname);
387
+ } catch {
388
+ return false;
389
+ }
390
+ }
391
+ function allowSensitiveRequest(headers, loopbackOnly) {
392
+ const { origin, host } = headers;
393
+ if (origin && origin.length > 0 && !originIsLoopback(origin)) return false;
394
+ if (loopbackOnly && host && host.length > 0 && !hostHeaderIsLoopback(host)) {
395
+ return false;
396
+ }
397
+ return true;
398
+ }
399
+
366
400
  // src/server/server.ts
367
401
  var DevtoolsServer = class {
368
402
  wss;
@@ -382,7 +416,12 @@ var DevtoolsServer = class {
382
416
  this._port = options.port ?? 4318;
383
417
  this.onData = options.onData;
384
418
  this.httpServer = options.server ?? http.createServer();
385
- this.wss = new ws.WebSocketServer({ server: this.httpServer, path: options.path ?? "/ws" });
419
+ const loopbackOnly = options.host == null || hostHeaderIsLoopback(options.host);
420
+ this.wss = new ws.WebSocketServer({
421
+ server: this.httpServer,
422
+ path: options.path ?? "/ws",
423
+ verifyClient: ({ origin, req }) => allowSensitiveRequest({ origin, host: req.headers.host }, loopbackOnly)
424
+ });
386
425
  this.wss.on("error", (err) => {
387
426
  if (this.httpServer.listening) throw err;
388
427
  });
@@ -1481,7 +1520,8 @@ function getWidgetJs() {
1481
1520
  }
1482
1521
  return cachedWidgetJs;
1483
1522
  }
1484
- function attachDevtoolsRoutes(httpServer, devtools) {
1523
+ function attachDevtoolsRoutes(httpServer, devtools, options = {}) {
1524
+ const loopbackOnly = options.loopbackOnly ?? true;
1485
1525
  httpServer.on("request", async (req, res) => {
1486
1526
  res.setHeader("Access-Control-Allow-Origin", "*");
1487
1527
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
@@ -1515,11 +1555,19 @@ function attachDevtoolsRoutes(httpServer, devtools) {
1515
1555
  return;
1516
1556
  }
1517
1557
  if (req.method === "GET" && url === "/v1/traces") {
1558
+ if (!allowSensitiveRequest(req.headers, loopbackOnly)) {
1559
+ sendJson(res, 403, { error: "Forbidden" });
1560
+ return;
1561
+ }
1518
1562
  const data = devtools.getCurrentData();
1519
1563
  sendJson(res, 200, { traces: data.traces, count: data.traces.length });
1520
1564
  return;
1521
1565
  }
1522
1566
  if (req.method === "DELETE" && url === "/v1/traces") {
1567
+ if (!allowSensitiveRequest(req.headers, loopbackOnly)) {
1568
+ sendJson(res, 403, { error: "Forbidden" });
1569
+ return;
1570
+ }
1523
1571
  devtools.clearData();
1524
1572
  sendJson(res, 200, { cleared: true });
1525
1573
  return;
@@ -1571,6 +1619,7 @@ exports.DevtoolsRemoteExporter = DevtoolsRemoteExporter;
1571
1619
  exports.DevtoolsServer = DevtoolsServer;
1572
1620
  exports.DevtoolsSpanExporter = DevtoolsSpanExporter;
1573
1621
  exports.ErrorAggregator = ErrorAggregator;
1622
+ exports.allowSensitiveRequest = allowSensitiveRequest;
1574
1623
  exports.appendManyWithLimit = appendManyWithLimit;
1575
1624
  exports.appendWithLimit = appendWithLimit;
1576
1625
  exports.applyTelemetryLimits = applyTelemetryLimits;
@@ -1579,7 +1628,10 @@ exports.createDevtoolsHttpServer = createDevtoolsHttpServer;
1579
1628
  exports.decodeOtlpLogsRequest = decodeOtlpLogsRequest;
1580
1629
  exports.decodeOtlpMetricsRequest = decodeOtlpMetricsRequest;
1581
1630
  exports.decodeOtlpTraceRequest = decodeOtlpTraceRequest;
1631
+ exports.hostHeaderIsLoopback = hostHeaderIsLoopback;
1632
+ exports.isLoopbackHostname = isLoopbackHostname;
1582
1633
  exports.isProtobufContentType = isProtobufContentType;
1634
+ exports.originIsLoopback = originIsLoopback;
1583
1635
  exports.parseOtlpLogs = parseOtlpLogs;
1584
1636
  exports.parseOtlpTraces = parseOtlpTraces;
1585
1637
  exports.probePortHolder = probePortHolder;