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.
package/dist/index.d.cts CHANGED
@@ -1,9 +1,9 @@
1
- import { D as DevtoolsServer, a as DevtoolsSpanExporter } from './exporter-DjLkU621.cjs';
2
- export { b as DevtoolsData, E as ErrorGroup, L as LogData, M as MetricData, S as SpanData, T as TraceData } from './exporter-DjLkU621.cjs';
1
+ import { D as DevtoolsServer, a as DevtoolsSpanExporter } from './exporter-De6p4iAD.cjs';
2
+ export { b as DevtoolsData, E as ErrorGroup, L as LogData, M as MetricData, S as SpanData, T as TraceData } from './exporter-De6p4iAD.cjs';
3
3
  import { Server } from 'node:http';
4
4
  export { DevtoolsLogExporter } from './server/log-exporter.cjs';
5
5
  export { DevtoolsRemoteExporter } from './server/remote-exporter.cjs';
6
- export { E as ErrorAggregator } from './error-aggregator-CbLiuot4.cjs';
6
+ export { E as ErrorAggregator } from './error-aggregator-D1Mr221Y.cjs';
7
7
  import '@opentelemetry/sdk-trace-base';
8
8
  import '@opentelemetry/core';
9
9
  import '@opentelemetry/sdk-logs';
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { D as DevtoolsServer, a as DevtoolsSpanExporter } from './exporter-DjLkU621.js';
2
- export { b as DevtoolsData, E as ErrorGroup, L as LogData, M as MetricData, S as SpanData, T as TraceData } from './exporter-DjLkU621.js';
1
+ import { D as DevtoolsServer, a as DevtoolsSpanExporter } from './exporter-De6p4iAD.js';
2
+ export { b as DevtoolsData, E as ErrorGroup, L as LogData, M as MetricData, S as SpanData, T as TraceData } from './exporter-De6p4iAD.js';
3
3
  import { Server } from 'node:http';
4
4
  export { DevtoolsLogExporter } from './server/log-exporter.js';
5
5
  export { DevtoolsRemoteExporter } from './server/remote-exporter.js';
6
- export { E as ErrorAggregator } from './error-aggregator-CAk_pt3Z.js';
6
+ export { E as ErrorAggregator } from './error-aggregator-D0Uu5r38.js';
7
7
  import '@opentelemetry/sdk-trace-base';
8
8
  import '@opentelemetry/core';
9
9
  import '@opentelemetry/sdk-logs';
package/dist/index.js CHANGED
@@ -348,6 +348,40 @@ function appendManyWithLimit(items, incoming, limit) {
348
348
  return next.length > limit ? next.slice(next.length - limit) : next;
349
349
  }
350
350
 
351
+ // src/server/origin-guard.ts
352
+ var LOOPBACK_IPV6 = /* @__PURE__ */ new Set(["::1", "0:0:0:0:0:0:0:1"]);
353
+ function isLoopbackHostname(hostname) {
354
+ const h = hostname.toLowerCase().replace(/^\[|\]$/g, "");
355
+ return h === "localhost" || /^127\./.test(h) || LOOPBACK_IPV6.has(h);
356
+ }
357
+ function hostnameFromHostHeader(host) {
358
+ const h = host.trim();
359
+ if (h.startsWith("[")) {
360
+ const end = h.indexOf("]");
361
+ return end > 0 ? h.slice(1, end) : h;
362
+ }
363
+ const colon = h.indexOf(":");
364
+ return colon === -1 ? h : h.slice(0, colon);
365
+ }
366
+ function hostHeaderIsLoopback(host) {
367
+ return isLoopbackHostname(hostnameFromHostHeader(host));
368
+ }
369
+ function originIsLoopback(origin) {
370
+ try {
371
+ return isLoopbackHostname(new URL(origin).hostname);
372
+ } catch {
373
+ return false;
374
+ }
375
+ }
376
+ function allowSensitiveRequest(headers, loopbackOnly) {
377
+ const { origin, host } = headers;
378
+ if (origin && origin.length > 0 && !originIsLoopback(origin)) return false;
379
+ if (loopbackOnly && host && host.length > 0 && !hostHeaderIsLoopback(host)) {
380
+ return false;
381
+ }
382
+ return true;
383
+ }
384
+
351
385
  // src/server/server.ts
352
386
  var DevtoolsServer = class {
353
387
  wss;
@@ -367,7 +401,12 @@ var DevtoolsServer = class {
367
401
  this._port = options.port ?? 4318;
368
402
  this.onData = options.onData;
369
403
  this.httpServer = options.server ?? createServer();
370
- this.wss = new WebSocketServer({ server: this.httpServer, path: options.path ?? "/ws" });
404
+ const loopbackOnly = options.host == null || hostHeaderIsLoopback(options.host);
405
+ this.wss = new WebSocketServer({
406
+ server: this.httpServer,
407
+ path: options.path ?? "/ws",
408
+ verifyClient: ({ origin, req }) => allowSensitiveRequest({ origin, host: req.headers.host }, loopbackOnly)
409
+ });
371
410
  this.wss.on("error", (err) => {
372
411
  if (this.httpServer.listening) throw err;
373
412
  });
@@ -985,7 +1024,8 @@ function getWidgetJs() {
985
1024
  }
986
1025
  return cachedWidgetJs;
987
1026
  }
988
- function attachDevtoolsRoutes(httpServer, devtools) {
1027
+ function attachDevtoolsRoutes(httpServer, devtools, options = {}) {
1028
+ const loopbackOnly = options.loopbackOnly ?? true;
989
1029
  httpServer.on("request", async (req, res) => {
990
1030
  res.setHeader("Access-Control-Allow-Origin", "*");
991
1031
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
@@ -1019,11 +1059,19 @@ function attachDevtoolsRoutes(httpServer, devtools) {
1019
1059
  return;
1020
1060
  }
1021
1061
  if (req.method === "GET" && url === "/v1/traces") {
1062
+ if (!allowSensitiveRequest(req.headers, loopbackOnly)) {
1063
+ sendJson(res, 403, { error: "Forbidden" });
1064
+ return;
1065
+ }
1022
1066
  const data = devtools.getCurrentData();
1023
1067
  sendJson(res, 200, { traces: data.traces, count: data.traces.length });
1024
1068
  return;
1025
1069
  }
1026
1070
  if (req.method === "DELETE" && url === "/v1/traces") {
1071
+ if (!allowSensitiveRequest(req.headers, loopbackOnly)) {
1072
+ sendJson(res, 403, { error: "Forbidden" });
1073
+ return;
1074
+ }
1027
1075
  devtools.clearData();
1028
1076
  sendJson(res, 200, { cleared: true });
1029
1077
  return;
@@ -1610,21 +1658,23 @@ var DevtoolsRemoteExporter = class {
1610
1658
  function createDevtools(options = {}) {
1611
1659
  const port = options.port ?? 4318;
1612
1660
  const host = options.host ?? "127.0.0.1";
1661
+ const loopbackOnly = hostHeaderIsLoopback(host);
1613
1662
  const httpServer = createServer();
1614
1663
  const wsServer = new DevtoolsServer({
1615
1664
  server: httpServer,
1665
+ host,
1616
1666
  verbose: options.verbose,
1617
1667
  maxHistory: options.maxHistory,
1618
1668
  maxTraceCount: options.maxTraceCount,
1619
1669
  maxLogCount: options.maxLogCount,
1620
1670
  maxMetricCount: options.maxMetricCount
1621
1671
  });
1622
- attachDevtoolsRoutes(httpServer, wsServer);
1672
+ attachDevtoolsRoutes(httpServer, wsServer, { loopbackOnly });
1623
1673
  const listeners = listenLoopbackDualStack({
1624
1674
  primary: httpServer,
1625
1675
  port,
1626
1676
  host,
1627
- attachSecondary: (s) => attachDevtoolsRoutes(s, wsServer)
1677
+ attachSecondary: (s) => attachDevtoolsRoutes(s, wsServer, { loopbackOnly })
1628
1678
  });
1629
1679
  if (options.verbose) {
1630
1680
  listeners.ready.then(({ warnings }) => {