nlcurl 0.6.0 → 0.7.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/cache/store.d.ts +89 -0
- package/dist/cache/store.d.ts.map +1 -0
- package/dist/cache/store.js +402 -0
- package/dist/cache/store.js.map +1 -0
- package/dist/cache/types.d.ts +101 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +2 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/cookies/jar.d.ts +11 -0
- package/dist/cookies/jar.d.ts.map +1 -1
- package/dist/cookies/jar.js +50 -4
- package/dist/cookies/jar.js.map +1 -1
- package/dist/cookies/parser.d.ts +2 -0
- package/dist/cookies/parser.d.ts.map +1 -1
- package/dist/cookies/parser.js +14 -0
- package/dist/cookies/parser.js.map +1 -1
- package/dist/cookies/psl-data.d.ts +1 -1
- package/dist/cookies/psl-data.js +1 -1
- package/dist/core/client.js +3 -0
- package/dist/core/client.js.map +1 -1
- package/dist/core/request.d.ts +68 -2
- package/dist/core/request.d.ts.map +1 -1
- package/dist/core/response.d.ts +22 -0
- package/dist/core/response.d.ts.map +1 -1
- package/dist/core/response.js +32 -0
- package/dist/core/response.js.map +1 -1
- package/dist/core/session.d.ts +23 -0
- package/dist/core/session.d.ts.map +1 -1
- package/dist/core/session.js +101 -3
- package/dist/core/session.js.map +1 -1
- package/dist/core/validation.d.ts +2 -1
- package/dist/core/validation.d.ts.map +1 -1
- package/dist/core/validation.js +5 -4
- package/dist/core/validation.js.map +1 -1
- package/dist/dns/codec.d.ts +37 -0
- package/dist/dns/codec.d.ts.map +1 -0
- package/dist/dns/codec.js +254 -0
- package/dist/dns/codec.js.map +1 -0
- package/dist/dns/doh-resolver.d.ts +52 -0
- package/dist/dns/doh-resolver.d.ts.map +1 -0
- package/dist/dns/doh-resolver.js +192 -0
- package/dist/dns/doh-resolver.js.map +1 -0
- package/dist/dns/https-rr.d.ts +51 -0
- package/dist/dns/https-rr.d.ts.map +1 -0
- package/dist/dns/https-rr.js +127 -0
- package/dist/dns/https-rr.js.map +1 -0
- package/dist/dns/types.d.ts +110 -0
- package/dist/dns/types.d.ts.map +1 -0
- package/dist/dns/types.js +34 -0
- package/dist/dns/types.js.map +1 -0
- package/dist/hsts/store.d.ts +41 -0
- package/dist/hsts/store.d.ts.map +1 -0
- package/dist/hsts/store.js +171 -0
- package/dist/hsts/store.js.map +1 -0
- package/dist/hsts/types.d.ts +28 -0
- package/dist/hsts/types.d.ts.map +1 -0
- package/dist/hsts/types.js +2 -0
- package/dist/hsts/types.js.map +1 -0
- package/dist/http/alt-svc.d.ts +85 -0
- package/dist/http/alt-svc.d.ts.map +1 -0
- package/dist/http/alt-svc.js +220 -0
- package/dist/http/alt-svc.js.map +1 -0
- package/dist/http/h1/client.d.ts.map +1 -1
- package/dist/http/h1/client.js +16 -0
- package/dist/http/h1/client.js.map +1 -1
- package/dist/http/h3/detection.d.ts +17 -0
- package/dist/http/h3/detection.d.ts.map +1 -0
- package/dist/http/h3/detection.js +59 -0
- package/dist/http/h3/detection.js.map +1 -0
- package/dist/http/negotiator.d.ts +24 -1
- package/dist/http/negotiator.d.ts.map +1 -1
- package/dist/http/negotiator.js +88 -18
- package/dist/http/negotiator.js.map +1 -1
- package/dist/http/pool.d.ts +2 -2
- package/dist/http/pool.d.ts.map +1 -1
- package/dist/http/pool.js.map +1 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/middleware/rate-limiter.d.ts.map +1 -1
- package/dist/middleware/rate-limiter.js +4 -0
- package/dist/middleware/rate-limiter.js.map +1 -1
- package/dist/proxy/env-proxy.d.ts +21 -0
- package/dist/proxy/env-proxy.d.ts.map +1 -0
- package/dist/proxy/env-proxy.js +74 -0
- package/dist/proxy/env-proxy.js.map +1 -0
- package/dist/proxy/http-proxy.d.ts +2 -0
- package/dist/proxy/http-proxy.d.ts.map +1 -1
- package/dist/proxy/http-proxy.js +19 -6
- package/dist/proxy/http-proxy.js.map +1 -1
- package/dist/proxy/socks.js +1 -1
- package/dist/proxy/socks.js.map +1 -1
- package/dist/sse/parser.d.ts +70 -0
- package/dist/sse/parser.d.ts.map +1 -0
- package/dist/sse/parser.js +153 -0
- package/dist/sse/parser.js.map +1 -0
- package/dist/tls/ech.d.ts +147 -0
- package/dist/tls/ech.d.ts.map +1 -0
- package/dist/tls/ech.js +401 -0
- package/dist/tls/ech.js.map +1 -0
- package/dist/tls/node-engine.d.ts +9 -1
- package/dist/tls/node-engine.d.ts.map +1 -1
- package/dist/tls/node-engine.js +39 -1
- package/dist/tls/node-engine.js.map +1 -1
- package/dist/tls/pin-verification.d.ts +9 -0
- package/dist/tls/pin-verification.d.ts.map +1 -0
- package/dist/tls/pin-verification.js +34 -0
- package/dist/tls/pin-verification.js.map +1 -0
- package/dist/tls/session-cache.d.ts +70 -0
- package/dist/tls/session-cache.d.ts.map +1 -0
- package/dist/tls/session-cache.js +80 -0
- package/dist/tls/session-cache.js.map +1 -0
- package/dist/tls/stealth/client-hello.d.ts +21 -0
- package/dist/tls/stealth/client-hello.d.ts.map +1 -1
- package/dist/tls/stealth/client-hello.js +116 -0
- package/dist/tls/stealth/client-hello.js.map +1 -1
- package/dist/tls/stealth/engine.d.ts.map +1 -1
- package/dist/tls/stealth/engine.js +152 -30
- package/dist/tls/stealth/engine.js.map +1 -1
- package/dist/tls/stealth/handshake.d.ts +2 -1
- package/dist/tls/stealth/handshake.d.ts.map +1 -1
- package/dist/tls/stealth/handshake.js +118 -5
- package/dist/tls/stealth/handshake.js.map +1 -1
- package/dist/tls/stealth/tls12-handshake.d.ts +14 -0
- package/dist/tls/stealth/tls12-handshake.d.ts.map +1 -0
- package/dist/tls/stealth/tls12-handshake.js +462 -0
- package/dist/tls/stealth/tls12-handshake.js.map +1 -0
- package/dist/tls/types.d.ts +16 -0
- package/dist/tls/types.d.ts.map +1 -1
- package/dist/utils/encoding.d.ts +8 -6
- package/dist/utils/encoding.d.ts.map +1 -1
- package/dist/utils/encoding.js +92 -24
- package/dist/utils/encoding.js.map +1 -1
- package/dist/utils/happy-eyeballs.d.ts +3 -0
- package/dist/utils/happy-eyeballs.d.ts.map +1 -1
- package/dist/utils/happy-eyeballs.js +42 -2
- package/dist/utils/happy-eyeballs.js.map +1 -1
- package/dist/ws/client.d.ts +3 -0
- package/dist/ws/client.d.ts.map +1 -1
- package/dist/ws/client.js +63 -7
- package/dist/ws/client.js.map +1 -1
- package/dist/ws/frame.d.ts +4 -2
- package/dist/ws/frame.d.ts.map +1 -1
- package/dist/ws/frame.js +8 -5
- package/dist/ws/frame.js.map +1 -1
- package/dist/ws/permessage-deflate.d.ts +58 -0
- package/dist/ws/permessage-deflate.d.ts.map +1 -0
- package/dist/ws/permessage-deflate.js +148 -0
- package/dist/ws/permessage-deflate.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { DoHConfig, DNSRecord } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* DNS-over-HTTPS resolver for encrypted DNS resolution.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* ```typescript
|
|
7
|
+
* const resolver = new DoHResolver({ server: "https://1.1.1.1/dns-query" });
|
|
8
|
+
* const records = await resolver.query("example.com", "A");
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare class DoHResolver {
|
|
12
|
+
private readonly serverUrl;
|
|
13
|
+
private readonly method;
|
|
14
|
+
private readonly timeout;
|
|
15
|
+
private readonly bootstrap;
|
|
16
|
+
private queryId;
|
|
17
|
+
constructor(config: DoHConfig);
|
|
18
|
+
/**
|
|
19
|
+
* Sends a DNS query over HTTPS and returns the parsed answer records.
|
|
20
|
+
*
|
|
21
|
+
* @param name Domain name to resolve.
|
|
22
|
+
* @param type Record type: "A", "AAAA", "HTTPS", or "SVCB".
|
|
23
|
+
* @param signal Optional AbortSignal for cancellation.
|
|
24
|
+
* @returns Array of raw DNS records from the answer section.
|
|
25
|
+
*/
|
|
26
|
+
query(name: string, type: "A" | "AAAA" | "HTTPS" | "SVCB", signal?: AbortSignal): Promise<DNSRecord[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Sends the DNS wire-format query to the DoH server.
|
|
29
|
+
*/
|
|
30
|
+
private sendQuery;
|
|
31
|
+
/**
|
|
32
|
+
* GET method: base64url-encode the DNS query in the `dns` query parameter.
|
|
33
|
+
*/
|
|
34
|
+
private sendGET;
|
|
35
|
+
/**
|
|
36
|
+
* POST method: send DNS wire-format directly in the request body.
|
|
37
|
+
*/
|
|
38
|
+
private sendPOST;
|
|
39
|
+
/**
|
|
40
|
+
* Make the HTTPS request with timeout and abort support.
|
|
41
|
+
*/
|
|
42
|
+
private httpRequest;
|
|
43
|
+
/**
|
|
44
|
+
* Resolves the DoH server hostname to an IP address (bootstrap).
|
|
45
|
+
* Uses the system DNS resolver for this bootstrap step to avoid
|
|
46
|
+
* a circular dependency (we can't use DoH to resolve the DoH server).
|
|
47
|
+
*
|
|
48
|
+
* If the server URL already uses an IP address, returns it directly.
|
|
49
|
+
*/
|
|
50
|
+
private resolveServerHost;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=doh-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doh-resolver.d.ts","sourceRoot":"","sources":["../../src/dns/doh-resolver.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AASvD;;;;;;;;GAQG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAM;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,OAAO,CAAK;gBAER,MAAM,EAAE,SAAS;IAO7B;;;;;;;OAOG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAS5G;;OAEG;YACW,SAAS;IASvB;;OAEG;IACH,OAAO,CAAC,OAAO;IAqBf;;OAEG;IACH,OAAO,CAAC,QAAQ;IAmBhB;;OAEG;IACH,OAAO,CAAC,WAAW;IA+EnB;;;;;;OAMG;YACW,iBAAiB;CAmBhC"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DNS-over-HTTPS (DoH) resolver implementing RFC 8484.
|
|
3
|
+
*
|
|
4
|
+
* Sends DNS queries over HTTPS to a configured DoH server, providing
|
|
5
|
+
* encrypted DNS resolution for privacy. Supports both GET (wire-format
|
|
6
|
+
* in query parameter) and POST (wire-format in body) methods.
|
|
7
|
+
*
|
|
8
|
+
* @see https://datatracker.ietf.org/doc/html/rfc8484
|
|
9
|
+
*/
|
|
10
|
+
import * as https from "node:https";
|
|
11
|
+
import * as http from "node:http";
|
|
12
|
+
import { lookup } from "node:dns/promises";
|
|
13
|
+
import { buildDNSQuery, parseDNSResponse } from "./codec.js";
|
|
14
|
+
import { RTYPE } from "./types.js";
|
|
15
|
+
const DOH_CONTENT_TYPE = "application/dns-message";
|
|
16
|
+
const DEFAULT_TIMEOUT = 5000;
|
|
17
|
+
/** Cache of bootstrapped DoH server IP → avoid infinite recursion. */
|
|
18
|
+
const bootstrapCache = new Map();
|
|
19
|
+
/**
|
|
20
|
+
* DNS-over-HTTPS resolver for encrypted DNS resolution.
|
|
21
|
+
*
|
|
22
|
+
* Usage:
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const resolver = new DoHResolver({ server: "https://1.1.1.1/dns-query" });
|
|
25
|
+
* const records = await resolver.query("example.com", "A");
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class DoHResolver {
|
|
29
|
+
serverUrl;
|
|
30
|
+
method;
|
|
31
|
+
timeout;
|
|
32
|
+
bootstrap;
|
|
33
|
+
queryId = 0;
|
|
34
|
+
constructor(config) {
|
|
35
|
+
this.serverUrl = new URL(config.server);
|
|
36
|
+
this.method = config.method ?? "POST";
|
|
37
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
38
|
+
this.bootstrap = config.bootstrap ?? true;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Sends a DNS query over HTTPS and returns the parsed answer records.
|
|
42
|
+
*
|
|
43
|
+
* @param name Domain name to resolve.
|
|
44
|
+
* @param type Record type: "A", "AAAA", "HTTPS", or "SVCB".
|
|
45
|
+
* @param signal Optional AbortSignal for cancellation.
|
|
46
|
+
* @returns Array of raw DNS records from the answer section.
|
|
47
|
+
*/
|
|
48
|
+
async query(name, type, signal) {
|
|
49
|
+
const rtype = RTYPE[type];
|
|
50
|
+
const id = this.queryId++ & 0xffff;
|
|
51
|
+
const queryPacket = buildDNSQuery(name, rtype, id);
|
|
52
|
+
const responseData = await this.sendQuery(queryPacket, signal);
|
|
53
|
+
return parseDNSResponse(responseData);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Sends the DNS wire-format query to the DoH server.
|
|
57
|
+
*/
|
|
58
|
+
async sendQuery(packet, signal) {
|
|
59
|
+
const host = await this.resolveServerHost();
|
|
60
|
+
if (this.method === "GET") {
|
|
61
|
+
return this.sendGET(packet, host, signal);
|
|
62
|
+
}
|
|
63
|
+
return this.sendPOST(packet, host, signal);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* GET method: base64url-encode the DNS query in the `dns` query parameter.
|
|
67
|
+
*/
|
|
68
|
+
sendGET(packet, host, signal) {
|
|
69
|
+
const encoded = packet.toString("base64url");
|
|
70
|
+
const url = new URL(this.serverUrl.toString());
|
|
71
|
+
url.searchParams.set("dns", encoded);
|
|
72
|
+
return this.httpRequest({
|
|
73
|
+
method: "GET",
|
|
74
|
+
hostname: host,
|
|
75
|
+
port: parseInt(this.serverUrl.port) || 443,
|
|
76
|
+
path: `${url.pathname}${url.search}`,
|
|
77
|
+
headers: {
|
|
78
|
+
accept: DOH_CONTENT_TYPE,
|
|
79
|
+
host: this.serverUrl.hostname,
|
|
80
|
+
},
|
|
81
|
+
}, undefined, signal);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* POST method: send DNS wire-format directly in the request body.
|
|
85
|
+
*/
|
|
86
|
+
sendPOST(packet, host, signal) {
|
|
87
|
+
return this.httpRequest({
|
|
88
|
+
method: "POST",
|
|
89
|
+
hostname: host,
|
|
90
|
+
port: parseInt(this.serverUrl.port) || 443,
|
|
91
|
+
path: this.serverUrl.pathname,
|
|
92
|
+
headers: {
|
|
93
|
+
"content-type": DOH_CONTENT_TYPE,
|
|
94
|
+
accept: DOH_CONTENT_TYPE,
|
|
95
|
+
"content-length": packet.length.toString(),
|
|
96
|
+
host: this.serverUrl.hostname,
|
|
97
|
+
},
|
|
98
|
+
}, packet, signal);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Make the HTTPS request with timeout and abort support.
|
|
102
|
+
*/
|
|
103
|
+
httpRequest(options, body, signal) {
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
if (signal?.aborted) {
|
|
106
|
+
reject(new Error("DoH query aborted"));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const isHTTPS = this.serverUrl.protocol === "https:";
|
|
110
|
+
const requestFn = isHTTPS ? https.request : http.request;
|
|
111
|
+
const tlsOpts = isHTTPS
|
|
112
|
+
? {
|
|
113
|
+
...options,
|
|
114
|
+
rejectUnauthorized: true,
|
|
115
|
+
servername: this.serverUrl.hostname,
|
|
116
|
+
}
|
|
117
|
+
: options;
|
|
118
|
+
const req = requestFn(tlsOpts, (res) => {
|
|
119
|
+
if (res.statusCode !== 200) {
|
|
120
|
+
req.destroy();
|
|
121
|
+
reject(new Error(`DoH server returned HTTP ${res.statusCode}`));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const contentType = res.headers["content-type"];
|
|
125
|
+
if (contentType && !contentType.includes(DOH_CONTENT_TYPE)) {
|
|
126
|
+
req.destroy();
|
|
127
|
+
reject(new Error(`DoH server returned unexpected content-type: ${contentType}`));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const chunks = [];
|
|
131
|
+
let totalSize = 0;
|
|
132
|
+
const MAX_DNS_RESPONSE = 65535;
|
|
133
|
+
res.on("data", (chunk) => {
|
|
134
|
+
totalSize += chunk.length;
|
|
135
|
+
if (totalSize > MAX_DNS_RESPONSE) {
|
|
136
|
+
req.destroy();
|
|
137
|
+
reject(new Error("DoH response exceeds maximum DNS message size"));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
chunks.push(chunk);
|
|
141
|
+
});
|
|
142
|
+
res.on("end", () => {
|
|
143
|
+
resolve(Buffer.concat(chunks));
|
|
144
|
+
});
|
|
145
|
+
res.on("error", reject);
|
|
146
|
+
});
|
|
147
|
+
req.on("error", reject);
|
|
148
|
+
const timer = setTimeout(() => {
|
|
149
|
+
req.destroy();
|
|
150
|
+
reject(new Error("DoH query timed out"));
|
|
151
|
+
}, this.timeout);
|
|
152
|
+
req.once("close", () => clearTimeout(timer));
|
|
153
|
+
if (signal) {
|
|
154
|
+
const onAbort = () => {
|
|
155
|
+
clearTimeout(timer);
|
|
156
|
+
req.destroy();
|
|
157
|
+
reject(new Error("DoH query aborted"));
|
|
158
|
+
};
|
|
159
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
160
|
+
req.once("close", () => signal.removeEventListener("abort", onAbort));
|
|
161
|
+
}
|
|
162
|
+
if (body) {
|
|
163
|
+
req.write(body);
|
|
164
|
+
}
|
|
165
|
+
req.end();
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Resolves the DoH server hostname to an IP address (bootstrap).
|
|
170
|
+
* Uses the system DNS resolver for this bootstrap step to avoid
|
|
171
|
+
* a circular dependency (we can't use DoH to resolve the DoH server).
|
|
172
|
+
*
|
|
173
|
+
* If the server URL already uses an IP address, returns it directly.
|
|
174
|
+
*/
|
|
175
|
+
async resolveServerHost() {
|
|
176
|
+
const host = this.serverUrl.hostname;
|
|
177
|
+
if (/^\d+\.\d+\.\d+\.\d+$/.test(host) || host.includes(":")) {
|
|
178
|
+
return host;
|
|
179
|
+
}
|
|
180
|
+
const cached = bootstrapCache.get(host);
|
|
181
|
+
if (cached)
|
|
182
|
+
return cached;
|
|
183
|
+
if (!this.bootstrap) {
|
|
184
|
+
return host;
|
|
185
|
+
}
|
|
186
|
+
const result = await lookup(host, { family: 0 });
|
|
187
|
+
const address = Array.isArray(result) ? result[0].address : result.address;
|
|
188
|
+
bootstrapCache.set(host, address);
|
|
189
|
+
return address;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=doh-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doh-resolver.js","sourceRoot":"","sources":["../../src/dns/doh-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type SVCBRecord, type DoHConfig, type ResolvedAddress } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Result of an HTTPS-RR lookup, combining SVCB records with address hints.
|
|
4
|
+
*/
|
|
5
|
+
export interface HTTPSRRResult {
|
|
6
|
+
/** Parsed SVCB/HTTPS records, sorted by priority (lowest first). */
|
|
7
|
+
svcb: SVCBRecord[];
|
|
8
|
+
/** ECH config list from the highest-priority record that has one. */
|
|
9
|
+
echConfigList?: Buffer;
|
|
10
|
+
/** ALPN protocols from the highest-priority ServiceMode record. */
|
|
11
|
+
alpn?: string[];
|
|
12
|
+
/** IP address hints extracted from SVCB records + A/AAAA. */
|
|
13
|
+
addresses: ResolvedAddress[];
|
|
14
|
+
/** Port override from the SVCB record, if any. */
|
|
15
|
+
port?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Resolver for HTTPS/SVCB DNS Resource Records (RFC 9460).
|
|
19
|
+
*
|
|
20
|
+
* Supports two modes:
|
|
21
|
+
* 1. **System DNS** — Uses `node:dns` (resolveAny or raw query).
|
|
22
|
+
* 2. **DoH** — Uses a DoHResolver for encrypted HTTPS-RR queries.
|
|
23
|
+
*/
|
|
24
|
+
export declare class HTTPSRRResolver {
|
|
25
|
+
private readonly dohResolver?;
|
|
26
|
+
private readonly systemResolver;
|
|
27
|
+
constructor(dohConfig?: DoHConfig);
|
|
28
|
+
/**
|
|
29
|
+
* Queries HTTPS records for a hostname and parses the results.
|
|
30
|
+
*
|
|
31
|
+
* @param hostname The domain to look up HTTPS records for.
|
|
32
|
+
* @param signal Optional AbortSignal for cancellation.
|
|
33
|
+
* @returns Parsed HTTPS-RR result with SVCB params, or null if no records found.
|
|
34
|
+
*/
|
|
35
|
+
resolve(hostname: string, signal?: AbortSignal): Promise<HTTPSRRResult | null>;
|
|
36
|
+
/**
|
|
37
|
+
* Resolves HTTPS records via DoH.
|
|
38
|
+
*/
|
|
39
|
+
private resolveViaDoH;
|
|
40
|
+
/**
|
|
41
|
+
* Resolves HTTPS records via the system DNS resolver.
|
|
42
|
+
* Uses raw DNS query + decode since node:dns doesn't natively support type 65.
|
|
43
|
+
*/
|
|
44
|
+
private resolveViaSystem;
|
|
45
|
+
/**
|
|
46
|
+
* Parses a native Node.js HTTPS DNS record into our SVCBRecord format.
|
|
47
|
+
* Node.js 22+ may return HTTPS records with a specific structure.
|
|
48
|
+
*/
|
|
49
|
+
private parseNativeHTTPSRecord;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=https-rr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"https-rr.d.ts","sourceRoot":"","sources":["../../src/dns/https-rr.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAS,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAE1F;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,6DAA6D;IAC7D,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAW;gBAE9B,SAAS,CAAC,EAAE,SAAS;IAOjC;;;;;;OAMG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IA+CpF;;OAEG;YACW,aAAa;IAK3B;;;OAGG;YACW,gBAAgB;IAU9B;;;OAGG;IACH,OAAO,CAAC,sBAAsB;CAc/B"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTPS Resource Record resolver (RFC 9460).
|
|
3
|
+
*
|
|
4
|
+
* Queries HTTPS/SVCB DNS records to discover:
|
|
5
|
+
* - ECH (Encrypted Client Hello) configuration keys
|
|
6
|
+
* - ALPN protocol hints (e.g. h2, h3)
|
|
7
|
+
* - IP address hints for faster connection setup
|
|
8
|
+
* - Port overrides
|
|
9
|
+
*
|
|
10
|
+
* Can use either the system DNS resolver (via `node:dns`) or a DoH
|
|
11
|
+
* resolver for encrypted queries.
|
|
12
|
+
*
|
|
13
|
+
* @see https://datatracker.ietf.org/doc/html/rfc9460
|
|
14
|
+
*/
|
|
15
|
+
import { Resolver } from "node:dns/promises";
|
|
16
|
+
import { DoHResolver } from "./doh-resolver.js";
|
|
17
|
+
import { parseSVCBRecord } from "./codec.js";
|
|
18
|
+
import { RTYPE } from "./types.js";
|
|
19
|
+
/**
|
|
20
|
+
* Resolver for HTTPS/SVCB DNS Resource Records (RFC 9460).
|
|
21
|
+
*
|
|
22
|
+
* Supports two modes:
|
|
23
|
+
* 1. **System DNS** — Uses `node:dns` (resolveAny or raw query).
|
|
24
|
+
* 2. **DoH** — Uses a DoHResolver for encrypted HTTPS-RR queries.
|
|
25
|
+
*/
|
|
26
|
+
export class HTTPSRRResolver {
|
|
27
|
+
dohResolver;
|
|
28
|
+
systemResolver;
|
|
29
|
+
constructor(dohConfig) {
|
|
30
|
+
if (dohConfig) {
|
|
31
|
+
this.dohResolver = new DoHResolver(dohConfig);
|
|
32
|
+
}
|
|
33
|
+
this.systemResolver = new Resolver();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Queries HTTPS records for a hostname and parses the results.
|
|
37
|
+
*
|
|
38
|
+
* @param hostname The domain to look up HTTPS records for.
|
|
39
|
+
* @param signal Optional AbortSignal for cancellation.
|
|
40
|
+
* @returns Parsed HTTPS-RR result with SVCB params, or null if no records found.
|
|
41
|
+
*/
|
|
42
|
+
async resolve(hostname, signal) {
|
|
43
|
+
try {
|
|
44
|
+
let svcbRecords;
|
|
45
|
+
if (this.dohResolver) {
|
|
46
|
+
svcbRecords = await this.resolveViaDoH(hostname, signal);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
svcbRecords = await this.resolveViaSystem(hostname);
|
|
50
|
+
}
|
|
51
|
+
if (svcbRecords.length === 0)
|
|
52
|
+
return null;
|
|
53
|
+
svcbRecords.sort((a, b) => a.priority - b.priority);
|
|
54
|
+
const serviceRecords = svcbRecords.filter((r) => r.priority > 0);
|
|
55
|
+
if (serviceRecords.length === 0)
|
|
56
|
+
return null;
|
|
57
|
+
const best = serviceRecords[0];
|
|
58
|
+
const addresses = [];
|
|
59
|
+
for (const rec of serviceRecords) {
|
|
60
|
+
if (rec.ipv4Hints) {
|
|
61
|
+
for (const addr of rec.ipv4Hints) {
|
|
62
|
+
addresses.push({ address: addr, family: 4 });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (rec.ipv6Hints) {
|
|
66
|
+
for (const addr of rec.ipv6Hints) {
|
|
67
|
+
addresses.push({ address: addr, family: 6 });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const echRecord = serviceRecords.find((r) => r.echConfigList);
|
|
72
|
+
return {
|
|
73
|
+
svcb: svcbRecords,
|
|
74
|
+
echConfigList: echRecord?.echConfigList,
|
|
75
|
+
alpn: best.alpn,
|
|
76
|
+
addresses,
|
|
77
|
+
port: best.port,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolves HTTPS records via DoH.
|
|
86
|
+
*/
|
|
87
|
+
async resolveViaDoH(hostname, signal) {
|
|
88
|
+
const records = await this.dohResolver.query(hostname, "HTTPS", signal);
|
|
89
|
+
return records.filter((r) => r.type === RTYPE.HTTPS || r.type === RTYPE.SVCB).map((r) => parseSVCBRecord(r.data));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Resolves HTTPS records via the system DNS resolver.
|
|
93
|
+
* Uses raw DNS query + decode since node:dns doesn't natively support type 65.
|
|
94
|
+
*/
|
|
95
|
+
async resolveViaSystem(hostname) {
|
|
96
|
+
try {
|
|
97
|
+
const results = await this.systemResolver.resolve(hostname, "HTTPS").catch(() => []);
|
|
98
|
+
if (Array.isArray(results) && results.length > 0) {
|
|
99
|
+
return results.map((r) => this.parseNativeHTTPSRecord(r));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch { }
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Parses a native Node.js HTTPS DNS record into our SVCBRecord format.
|
|
107
|
+
* Node.js 22+ may return HTTPS records with a specific structure.
|
|
108
|
+
*/
|
|
109
|
+
parseNativeHTTPSRecord(record) {
|
|
110
|
+
const result = {
|
|
111
|
+
priority: record.priority ?? 0,
|
|
112
|
+
target: record.target ?? "",
|
|
113
|
+
};
|
|
114
|
+
if (record.alpn)
|
|
115
|
+
result.alpn = Array.isArray(record.alpn) ? record.alpn : [record.alpn];
|
|
116
|
+
if (record.port)
|
|
117
|
+
result.port = record.port;
|
|
118
|
+
if (record.ipv4hint)
|
|
119
|
+
result.ipv4Hints = Array.isArray(record.ipv4hint) ? record.ipv4hint : [record.ipv4hint];
|
|
120
|
+
if (record.ipv6hint)
|
|
121
|
+
result.ipv6Hints = Array.isArray(record.ipv6hint) ? record.ipv6hint : [record.ipv6hint];
|
|
122
|
+
if (record.ech)
|
|
123
|
+
result.echConfigList = Buffer.isBuffer(record.ech) ? record.ech : Buffer.from(record.ech, "base64");
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=https-rr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"https-rr.js","sourceRoot":"","sources":["../../src/dns/https-rr.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the DNS resolution subsystem, including DNS-over-HTTPS
|
|
3
|
+
* (RFC 8484), HTTPS/SVCB resource records (RFC 9460), and resolver interfaces.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A resolved IP address entry.
|
|
7
|
+
*/
|
|
8
|
+
export interface ResolvedAddress {
|
|
9
|
+
address: string;
|
|
10
|
+
family: 4 | 6;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* DNS query types used by the resolver.
|
|
14
|
+
*/
|
|
15
|
+
export type DNSRecordType = "A" | "AAAA" | "HTTPS" | "SVCB";
|
|
16
|
+
/**
|
|
17
|
+
* A parsed DNS resource record.
|
|
18
|
+
*/
|
|
19
|
+
export interface DNSRecord {
|
|
20
|
+
name: string;
|
|
21
|
+
type: number;
|
|
22
|
+
ttl: number;
|
|
23
|
+
data: Buffer;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Wire-format DNS record type numbers.
|
|
27
|
+
*/
|
|
28
|
+
export declare const RTYPE: {
|
|
29
|
+
readonly A: 1;
|
|
30
|
+
readonly AAAA: 28;
|
|
31
|
+
readonly HTTPS: 65;
|
|
32
|
+
readonly SVCB: 64;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Wire-format DNS class numbers.
|
|
36
|
+
*/
|
|
37
|
+
export declare const RCLASS: {
|
|
38
|
+
readonly IN: 1;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* SvcParam keys defined in RFC 9460 §14.3.
|
|
42
|
+
*/
|
|
43
|
+
export declare const SvcParamKey: {
|
|
44
|
+
readonly MANDATORY: 0;
|
|
45
|
+
readonly ALPN: 1;
|
|
46
|
+
readonly NO_DEFAULT_ALPN: 2;
|
|
47
|
+
readonly PORT: 3;
|
|
48
|
+
readonly IPV4HINT: 4;
|
|
49
|
+
readonly ECH: 5;
|
|
50
|
+
readonly IPV6HINT: 6;
|
|
51
|
+
/** draft-ietf-dnsop-svcb-https §14 — DNS-over-HTTPS path template */
|
|
52
|
+
readonly DOHPATH: 7;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Parsed HTTPS/SVCB record service parameters (RFC 9460).
|
|
56
|
+
*/
|
|
57
|
+
export interface SVCBRecord {
|
|
58
|
+
/** SvcPriority — 0 = AliasMode, >0 = ServiceMode. */
|
|
59
|
+
priority: number;
|
|
60
|
+
/** TargetName — the target domain (empty = use record owner). */
|
|
61
|
+
target: string;
|
|
62
|
+
/** ALPN protocol identifiers (e.g. ["h2", "h3"]). */
|
|
63
|
+
alpn?: string[];
|
|
64
|
+
/** TCP port override. */
|
|
65
|
+
port?: number;
|
|
66
|
+
/** IPv4 address hints. */
|
|
67
|
+
ipv4Hints?: string[];
|
|
68
|
+
/** IPv6 address hints. */
|
|
69
|
+
ipv6Hints?: string[];
|
|
70
|
+
/** ECH configuration (raw bytes). */
|
|
71
|
+
echConfigList?: Buffer;
|
|
72
|
+
/** Whether no-default-alpn is set. */
|
|
73
|
+
noDefaultAlpn?: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Configuration options for the DoH resolver.
|
|
77
|
+
*/
|
|
78
|
+
export interface DoHConfig {
|
|
79
|
+
/** DoH server URL (e.g. "https://1.1.1.1/dns-query"). */
|
|
80
|
+
server: string;
|
|
81
|
+
/**
|
|
82
|
+
* HTTP method for DoH queries.
|
|
83
|
+
* - `"GET"`: DNS wire-format base64url-encoded in `?dns=` query parameter.
|
|
84
|
+
* - `"POST"`: DNS wire-format in request body.
|
|
85
|
+
* @default "POST"
|
|
86
|
+
*/
|
|
87
|
+
method?: "GET" | "POST";
|
|
88
|
+
/** Timeout in ms for each DoH query. @default 5000 */
|
|
89
|
+
timeout?: number;
|
|
90
|
+
/**
|
|
91
|
+
* Whether to bootstrap the DoH server address via system DNS if the
|
|
92
|
+
* server URL uses a hostname instead of an IP.
|
|
93
|
+
* @default true
|
|
94
|
+
*/
|
|
95
|
+
bootstrap?: boolean;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Combined DNS configuration for the library.
|
|
99
|
+
*/
|
|
100
|
+
export interface DNSConfig {
|
|
101
|
+
/** DoH resolver configuration. When set, DNS queries use DNS-over-HTTPS. */
|
|
102
|
+
doh?: DoHConfig;
|
|
103
|
+
/**
|
|
104
|
+
* Whether to query HTTPS/SVCB records alongside A/AAAA.
|
|
105
|
+
* Enables ECH key discovery, ALPN hints, and IP hints.
|
|
106
|
+
* @default false
|
|
107
|
+
*/
|
|
108
|
+
httpsRR?: boolean;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dns/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;CACf;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,GAAG,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,eAAO,MAAM,KAAK;;;;;CAKR,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,MAAM;;CAET,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;IAQtB,qEAAqE;;CAE7D,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,yBAAyB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACxB,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,4EAA4E;IAC5E,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the DNS resolution subsystem, including DNS-over-HTTPS
|
|
3
|
+
* (RFC 8484), HTTPS/SVCB resource records (RFC 9460), and resolver interfaces.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Wire-format DNS record type numbers.
|
|
7
|
+
*/
|
|
8
|
+
export const RTYPE = {
|
|
9
|
+
A: 1,
|
|
10
|
+
AAAA: 28,
|
|
11
|
+
HTTPS: 65,
|
|
12
|
+
SVCB: 64,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Wire-format DNS class numbers.
|
|
16
|
+
*/
|
|
17
|
+
export const RCLASS = {
|
|
18
|
+
IN: 1,
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* SvcParam keys defined in RFC 9460 §14.3.
|
|
22
|
+
*/
|
|
23
|
+
export const SvcParamKey = {
|
|
24
|
+
MANDATORY: 0,
|
|
25
|
+
ALPN: 1,
|
|
26
|
+
NO_DEFAULT_ALPN: 2,
|
|
27
|
+
PORT: 3,
|
|
28
|
+
IPV4HINT: 4,
|
|
29
|
+
ECH: 5,
|
|
30
|
+
IPV6HINT: 6,
|
|
31
|
+
/** draft-ietf-dnsop-svcb-https §14 — DNS-over-HTTPS path template */
|
|
32
|
+
DOHPATH: 7,
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/dns/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyBH;;GAEG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,CAAC,EAAE,CAAC;IACJ,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,EAAE;CACA,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,EAAE,EAAE,CAAC;CACG,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,SAAS,EAAE,CAAC;IACZ,IAAI,EAAE,CAAC;IACP,eAAe,EAAE,CAAC;IAClB,IAAI,EAAE,CAAC;IACP,QAAQ,EAAE,CAAC;IACX,GAAG,EAAE,CAAC;IACN,QAAQ,EAAE,CAAC;IACX,qEAAqE;IACrE,OAAO,EAAE,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { HSTSConfig } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* In-memory HSTS policy store implementing RFC 6797.
|
|
4
|
+
*
|
|
5
|
+
* Parses `Strict-Transport-Security` response headers, stores per-host policies,
|
|
6
|
+
* and upgrades `http://` URLs to `https://` when an active policy matches.
|
|
7
|
+
*/
|
|
8
|
+
export declare class HSTSStore {
|
|
9
|
+
private readonly policies;
|
|
10
|
+
constructor(config?: HSTSConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Seeds a preload entry with a very long max-age (20 years).
|
|
13
|
+
*/
|
|
14
|
+
private addPreload;
|
|
15
|
+
/**
|
|
16
|
+
* Parses a `Strict-Transport-Security` header value and stores the policy.
|
|
17
|
+
* Only processes headers received over a secure (HTTPS) connection, as
|
|
18
|
+
* required by RFC 6797 §8.1.
|
|
19
|
+
*
|
|
20
|
+
* @param host - The hostname from the request URL.
|
|
21
|
+
* @param value - The raw STS header value (e.g. `"max-age=31536000; includeSubDomains"`).
|
|
22
|
+
* @param isSecure - Whether the response was received over HTTPS.
|
|
23
|
+
*/
|
|
24
|
+
parseHeader(host: string, value: string, isSecure: boolean): void;
|
|
25
|
+
/**
|
|
26
|
+
* Checks whether the given host has an active HSTS policy, either via
|
|
27
|
+
* congruent match or superdomain match with `includeSubDomains`.
|
|
28
|
+
*/
|
|
29
|
+
isSecure(host: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* If there is an active HSTS policy for the host in the given URL,
|
|
32
|
+
* upgrades the scheme from `http:` to `https:`. Returns the original
|
|
33
|
+
* URL string if no upgrade is needed.
|
|
34
|
+
*/
|
|
35
|
+
upgradeURL(urlString: string): string;
|
|
36
|
+
/** Returns the number of active policies stored. */
|
|
37
|
+
get size(): number;
|
|
38
|
+
/** Clears all stored policies. */
|
|
39
|
+
clear(): void;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/hsts/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA+B,MAAM,YAAY,CAAC;AAE1E;;;;;GAKG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;gBAE7C,MAAM,CAAC,EAAE,UAAU;IAQ/B;;OAEG;IACH,OAAO,CAAC,UAAU;IAUlB;;;;;;;;OAQG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI;IA2BjE;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAwB/B;;;;OAIG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAkBrC,oDAAoD;IACpD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,kCAAkC;IAClC,KAAK,IAAI,IAAI;CAGd"}
|