@dnsid-ai/transport 0.26.0 → 0.27.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.cjs CHANGED
@@ -46,6 +46,7 @@ var fs = __toESM(require("fs"), 1);
46
46
  var https = __toESM(require("https"), 1);
47
47
  var net2 = __toESM(require("net"), 1);
48
48
  var tls = __toESM(require("tls"), 1);
49
+ var import_node_stream = require("stream");
49
50
  var import_undici = require("undici");
50
51
  var import_protocol2 = require("@dnsid-ai/protocol");
51
52
 
@@ -190,7 +191,8 @@ function createSsrfSafeFetch(config = {}, options = {}) {
190
191
  const privateAddressHosts = (options.privateAddressHosts ?? []).map(import_protocol2.normalizePrivateAddressHost);
191
192
  const connect2 = { lookup: createSsrfSafeLookup(config.dnsServer, privateAddressHosts) };
192
193
  if (config.caBundlePath) connect2.ca = [...tls.rootCertificates, fs.readFileSync(config.caBundlePath, "utf8")];
193
- const fetchWithSafeLookup = createFetchWithDispatcher(new import_undici.Agent({ connect: connect2 }));
194
+ const dispatcher = new import_undici.Agent({ connect: connect2 });
195
+ const fetchWithSafeLookup = createFetchWithDispatcher(dispatcher);
194
196
  return async (input, init) => {
195
197
  const url = new URL(input instanceof Request ? input.url : input);
196
198
  if (isUnsafeIp(url.hostname)) {
@@ -198,6 +200,26 @@ function createSsrfSafeFetch(config = {}, options = {}) {
198
200
  code: import_protocol2.VerificationCode.TLSError
199
201
  });
200
202
  }
203
+ if (options.decompress === false) {
204
+ const { url: target, init: normalized } = normalizeFetchArgs(input, { ...init, redirect: "manual" });
205
+ const request = new Request(target, normalized);
206
+ const targetUrl = new URL(request.url);
207
+ const response = await dispatcher.request({
208
+ origin: targetUrl.origin,
209
+ path: targetUrl.pathname + targetUrl.search,
210
+ method: request.method,
211
+ headers: Object.fromEntries(request.headers),
212
+ body: request.body ? import_node_stream.Readable.fromWeb(request.body) : void 0,
213
+ signal: request.signal
214
+ });
215
+ const headers = new Headers();
216
+ for (const [name, value] of Object.entries(response.headers)) {
217
+ for (const item of Array.isArray(value) ? value : value === void 0 ? [] : [value]) headers.append(name, item);
218
+ }
219
+ const noBody = request.method === "HEAD" || [204, 205, 304].includes(response.statusCode);
220
+ if (noBody) await response.body.dump();
221
+ return new Response(noBody ? null : import_node_stream.Readable.toWeb(response.body), { status: response.statusCode, statusText: response.statusText, headers });
222
+ }
201
223
  return fetchWithSafeLookup(input, { ...init, redirect: "manual" });
202
224
  };
203
225
  }
package/dist/index.d.cts CHANGED
@@ -33,6 +33,8 @@ interface HTTPSFetchOptions {
33
33
 
34
34
  /** Explicit exceptions for trusted test/private deployments using {@link createSsrfSafeFetch}. */
35
35
  interface SsrfSafeFetchOptions {
36
+ /** Set false to preserve encoded response bytes and Content-Encoding, for signed-directory verification. Default: true. */
37
+ decompress?: boolean;
36
38
  /**
37
39
  * Hostnames, or leading-dot suffixes such as `.test`, whose resolved RFC 1918/ULA private or
38
40
  * loopback addresses may be contacted. Link-local and other unsafe ranges remain blocked, IP-literal
package/dist/index.d.ts CHANGED
@@ -33,6 +33,8 @@ interface HTTPSFetchOptions {
33
33
 
34
34
  /** Explicit exceptions for trusted test/private deployments using {@link createSsrfSafeFetch}. */
35
35
  interface SsrfSafeFetchOptions {
36
+ /** Set false to preserve encoded response bytes and Content-Encoding, for signed-directory verification. Default: true. */
37
+ decompress?: boolean;
36
38
  /**
37
39
  * Hostnames, or leading-dot suffixes such as `.test`, whose resolved RFC 1918/ULA private or
38
40
  * loopback addresses may be contacted. Link-local and other unsafe ranges remain blocked, IP-literal
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import * as fs from "fs";
4
4
  import * as https from "https";
5
5
  import * as net2 from "net";
6
6
  import * as tls from "tls";
7
+ import { Readable } from "stream";
7
8
  import { Agent as Agent2, fetch as undiciFetch } from "undici";
8
9
  import { ArgumentError, DNSSECState as DNSSECState2, VerificationCode, VerificationError, normalizePrivateAddressHost } from "@dnsid-ai/protocol";
9
10
 
@@ -148,7 +149,8 @@ function createSsrfSafeFetch(config = {}, options = {}) {
148
149
  const privateAddressHosts = (options.privateAddressHosts ?? []).map(normalizePrivateAddressHost);
149
150
  const connect2 = { lookup: createSsrfSafeLookup(config.dnsServer, privateAddressHosts) };
150
151
  if (config.caBundlePath) connect2.ca = [...tls.rootCertificates, fs.readFileSync(config.caBundlePath, "utf8")];
151
- const fetchWithSafeLookup = createFetchWithDispatcher(new Agent2({ connect: connect2 }));
152
+ const dispatcher = new Agent2({ connect: connect2 });
153
+ const fetchWithSafeLookup = createFetchWithDispatcher(dispatcher);
152
154
  return async (input, init) => {
153
155
  const url = new URL(input instanceof Request ? input.url : input);
154
156
  if (isUnsafeIp(url.hostname)) {
@@ -156,6 +158,26 @@ function createSsrfSafeFetch(config = {}, options = {}) {
156
158
  code: VerificationCode.TLSError
157
159
  });
158
160
  }
161
+ if (options.decompress === false) {
162
+ const { url: target, init: normalized } = normalizeFetchArgs(input, { ...init, redirect: "manual" });
163
+ const request = new Request(target, normalized);
164
+ const targetUrl = new URL(request.url);
165
+ const response = await dispatcher.request({
166
+ origin: targetUrl.origin,
167
+ path: targetUrl.pathname + targetUrl.search,
168
+ method: request.method,
169
+ headers: Object.fromEntries(request.headers),
170
+ body: request.body ? Readable.fromWeb(request.body) : void 0,
171
+ signal: request.signal
172
+ });
173
+ const headers = new Headers();
174
+ for (const [name, value] of Object.entries(response.headers)) {
175
+ for (const item of Array.isArray(value) ? value : value === void 0 ? [] : [value]) headers.append(name, item);
176
+ }
177
+ const noBody = request.method === "HEAD" || [204, 205, 304].includes(response.statusCode);
178
+ if (noBody) await response.body.dump();
179
+ return new Response(noBody ? null : Readable.toWeb(response.body), { status: response.statusCode, statusText: response.statusText, headers });
180
+ }
159
181
  return fetchWithSafeLookup(input, { ...init, redirect: "manual" });
160
182
  };
161
183
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dnsid-ai/transport",
3
- "version": "0.26.0",
3
+ "version": "0.27.0",
4
4
  "description": "Node.js DNS and HTTPS transport implementations for DNSid.",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -38,7 +38,7 @@
38
38
  "typecheck": "tsc --noEmit"
39
39
  },
40
40
  "dependencies": {
41
- "@dnsid-ai/protocol": "^0.26.0",
41
+ "@dnsid-ai/protocol": "^0.27.0",
42
42
  "dns-packet": "5.6.1",
43
43
  "undici": "^8.11.0"
44
44
  },