httpcloak 1.5.1 → 1.5.2
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/README.md +111 -1
- package/lib/index.d.ts +85 -34
- package/lib/index.js +11 -1
- package/npm/darwin-arm64/package.json +1 -1
- package/npm/darwin-x64/package.json +1 -1
- package/npm/linux-arm64/package.json +1 -1
- package/npm/linux-x64/package.json +1 -1
- package/npm/win32-arm64/package.json +1 -1
- package/npm/win32-x64/package.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,13 +99,123 @@ session.postCb(
|
|
|
99
99
|
);
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
## Proxy Support
|
|
103
|
+
|
|
104
|
+
HTTPCloak supports HTTP, SOCKS5, and HTTP/3 (MASQUE) proxies with full fingerprint preservation.
|
|
105
|
+
|
|
106
|
+
### HTTP Proxy
|
|
103
107
|
|
|
104
108
|
```javascript
|
|
109
|
+
const { Session } = require("httpcloak");
|
|
110
|
+
|
|
111
|
+
// Basic HTTP proxy
|
|
105
112
|
const session = new Session({
|
|
113
|
+
preset: "chrome-143",
|
|
114
|
+
proxy: "http://host:port",
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// With authentication
|
|
118
|
+
const sessionAuth = new Session({
|
|
106
119
|
preset: "chrome-143",
|
|
107
120
|
proxy: "http://user:pass@host:port",
|
|
108
121
|
});
|
|
122
|
+
|
|
123
|
+
// HTTPS proxy
|
|
124
|
+
const sessionHttps = new Session({
|
|
125
|
+
preset: "chrome-143",
|
|
126
|
+
proxy: "https://user:pass@host:port",
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### SOCKS5 Proxy
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
const { Session } = require("httpcloak");
|
|
134
|
+
|
|
135
|
+
// SOCKS5 proxy (with DNS resolution on proxy)
|
|
136
|
+
const session = new Session({
|
|
137
|
+
preset: "chrome-143",
|
|
138
|
+
proxy: "socks5h://host:port",
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// With authentication
|
|
142
|
+
const sessionAuth = new Session({
|
|
143
|
+
preset: "chrome-143",
|
|
144
|
+
proxy: "socks5h://user:pass@host:port",
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const response = await session.get("https://www.cloudflare.com/cdn-cgi/trace");
|
|
148
|
+
console.log(response.protocol); // h3 (HTTP/3 through SOCKS5!)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### HTTP/3 MASQUE Proxy
|
|
152
|
+
|
|
153
|
+
MASQUE (RFC 9484) enables HTTP/3 connections through compatible proxies:
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
const { Session } = require("httpcloak");
|
|
157
|
+
|
|
158
|
+
// MASQUE proxy (auto-detected for known providers like Bright Data)
|
|
159
|
+
const session = new Session({
|
|
160
|
+
preset: "chrome-143",
|
|
161
|
+
proxy: "https://user:pass@brd.superproxy.io:10001",
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const response = await session.get("https://www.cloudflare.com/cdn-cgi/trace");
|
|
165
|
+
console.log(response.protocol); // h3
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Advanced Features
|
|
169
|
+
|
|
170
|
+
### Encrypted Client Hello (ECH)
|
|
171
|
+
|
|
172
|
+
ECH encrypts the SNI (Server Name Indication) to prevent traffic analysis. Works with all Cloudflare domains:
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
const { Session } = require("httpcloak");
|
|
176
|
+
|
|
177
|
+
// Enable ECH for Cloudflare domains
|
|
178
|
+
const session = new Session({
|
|
179
|
+
preset: "chrome-143",
|
|
180
|
+
echConfigDomain: "cloudflare-ech.com",
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const response = await session.get("https://www.cloudflare.com/cdn-cgi/trace");
|
|
184
|
+
console.log(response.text);
|
|
185
|
+
// Output includes: sni=encrypted, http=http/3
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Domain Fronting (Connect-To)
|
|
189
|
+
|
|
190
|
+
Connect to one server while requesting a different domain:
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
const { Session } = require("httpcloak");
|
|
194
|
+
|
|
195
|
+
// Connect to claude.ai's IP but request www.cloudflare.com
|
|
196
|
+
const session = new Session({
|
|
197
|
+
preset: "chrome-143",
|
|
198
|
+
connectTo: { "www.cloudflare.com": "claude.ai" },
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const response = await session.get("https://www.cloudflare.com/cdn-cgi/trace");
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Combined: SOCKS5 + ECH
|
|
205
|
+
|
|
206
|
+
Get HTTP/3 with encrypted SNI through a SOCKS5 proxy:
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
const { Session } = require("httpcloak");
|
|
210
|
+
|
|
211
|
+
const session = new Session({
|
|
212
|
+
preset: "chrome-143",
|
|
213
|
+
proxy: "socks5h://user:pass@host:port",
|
|
214
|
+
echConfigDomain: "cloudflare-ech.com",
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const response = await session.get("https://www.cloudflare.com/cdn-cgi/trace");
|
|
218
|
+
// Response shows: http=http/3, sni=encrypted
|
|
109
219
|
```
|
|
110
220
|
|
|
111
221
|
## Cookie Management
|
package/lib/index.d.ts
CHANGED
|
@@ -6,6 +6,22 @@ export class HTTPCloakError extends Error {
|
|
|
6
6
|
name: "HTTPCloakError";
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
export class Cookie {
|
|
10
|
+
/** Cookie name */
|
|
11
|
+
name: string;
|
|
12
|
+
/** Cookie value */
|
|
13
|
+
value: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class RedirectInfo {
|
|
17
|
+
/** HTTP status code */
|
|
18
|
+
statusCode: number;
|
|
19
|
+
/** Request URL */
|
|
20
|
+
url: string;
|
|
21
|
+
/** Response headers */
|
|
22
|
+
headers: Record<string, string>;
|
|
23
|
+
}
|
|
24
|
+
|
|
9
25
|
export class Response {
|
|
10
26
|
/** HTTP status code */
|
|
11
27
|
statusCode: number;
|
|
@@ -13,21 +29,40 @@ export class Response {
|
|
|
13
29
|
headers: Record<string, string>;
|
|
14
30
|
/** Raw response body as Buffer */
|
|
15
31
|
body: Buffer;
|
|
32
|
+
/** Response body as Buffer (alias for body) */
|
|
33
|
+
content: Buffer;
|
|
16
34
|
/** Response body as string */
|
|
17
35
|
text: string;
|
|
18
36
|
/** Final URL after redirects */
|
|
19
37
|
finalUrl: string;
|
|
38
|
+
/** Final URL after redirects (alias for finalUrl) */
|
|
39
|
+
url: string;
|
|
20
40
|
/** Protocol used (http/1.1, h2, h3) */
|
|
21
41
|
protocol: string;
|
|
42
|
+
/** Elapsed time in milliseconds */
|
|
43
|
+
elapsed: number;
|
|
44
|
+
/** Cookies set by this response */
|
|
45
|
+
cookies: Cookie[];
|
|
46
|
+
/** Redirect history */
|
|
47
|
+
history: RedirectInfo[];
|
|
48
|
+
/** True if status code < 400 */
|
|
49
|
+
ok: boolean;
|
|
50
|
+
/** HTTP status reason phrase (e.g., 'OK', 'Not Found') */
|
|
51
|
+
reason: string;
|
|
52
|
+
/** Response encoding from Content-Type header */
|
|
53
|
+
encoding: string | null;
|
|
22
54
|
|
|
23
55
|
/** Parse response body as JSON */
|
|
24
56
|
json<T = any>(): T;
|
|
57
|
+
|
|
58
|
+
/** Raise error if status >= 400 */
|
|
59
|
+
raiseForStatus(): void;
|
|
25
60
|
}
|
|
26
61
|
|
|
27
62
|
export interface SessionOptions {
|
|
28
63
|
/** Browser preset to use (default: "chrome-143") */
|
|
29
64
|
preset?: string;
|
|
30
|
-
/** Proxy URL (e.g., "http://user:pass@host:port") */
|
|
65
|
+
/** Proxy URL (e.g., "http://user:pass@host:port" or "socks5://host:port") */
|
|
31
66
|
proxy?: string;
|
|
32
67
|
/** Request timeout in seconds (default: 30) */
|
|
33
68
|
timeout?: number;
|
|
@@ -43,17 +78,33 @@ export interface SessionOptions {
|
|
|
43
78
|
retry?: number;
|
|
44
79
|
/** Status codes to retry on (default: [429, 500, 502, 503, 504]) */
|
|
45
80
|
retryOnStatus?: number[];
|
|
81
|
+
/** Prefer IPv4 addresses over IPv6 (default: false) */
|
|
82
|
+
preferIpv4?: boolean;
|
|
83
|
+
/** Default basic auth [username, password] */
|
|
84
|
+
auth?: [string, string];
|
|
85
|
+
/** Domain fronting map {requestHost: connectHost} - DNS resolves connectHost but SNI/Host uses requestHost */
|
|
86
|
+
connectTo?: Record<string, string>;
|
|
87
|
+
/** Domain to fetch ECH config from (e.g., "cloudflare-ech.com" for any Cloudflare domain) */
|
|
88
|
+
echConfigDomain?: string;
|
|
46
89
|
}
|
|
47
90
|
|
|
48
91
|
export interface RequestOptions {
|
|
49
|
-
/** HTTP method */
|
|
50
|
-
method: string;
|
|
51
|
-
/** Request URL */
|
|
52
|
-
url: string;
|
|
53
92
|
/** Optional custom headers */
|
|
54
93
|
headers?: Record<string, string>;
|
|
55
|
-
/** Optional request body */
|
|
94
|
+
/** Optional request body (for POST, PUT, PATCH) */
|
|
56
95
|
body?: string | Buffer | Record<string, any>;
|
|
96
|
+
/** JSON body (will be serialized) */
|
|
97
|
+
json?: Record<string, any>;
|
|
98
|
+
/** Form data (will be URL encoded) */
|
|
99
|
+
data?: Record<string, any>;
|
|
100
|
+
/** Files to upload as multipart/form-data */
|
|
101
|
+
files?: Record<string, Buffer | { filename: string; content: Buffer; contentType?: string }>;
|
|
102
|
+
/** Query parameters */
|
|
103
|
+
params?: Record<string, string | number | boolean>;
|
|
104
|
+
/** Cookies to send with this request */
|
|
105
|
+
cookies?: Record<string, string>;
|
|
106
|
+
/** Basic auth [username, password] */
|
|
107
|
+
auth?: [string, string];
|
|
57
108
|
/** Optional request timeout in seconds */
|
|
58
109
|
timeout?: number;
|
|
59
110
|
}
|
|
@@ -61,67 +112,66 @@ export interface RequestOptions {
|
|
|
61
112
|
export class Session {
|
|
62
113
|
constructor(options?: SessionOptions);
|
|
63
114
|
|
|
115
|
+
/** Default headers for all requests */
|
|
116
|
+
headers: Record<string, string>;
|
|
117
|
+
|
|
118
|
+
/** Default auth for all requests [username, password] */
|
|
119
|
+
auth: [string, string] | null;
|
|
120
|
+
|
|
64
121
|
/** Close the session and release resources */
|
|
65
122
|
close(): void;
|
|
66
123
|
|
|
67
124
|
// Synchronous methods
|
|
68
125
|
/** Perform a synchronous GET request */
|
|
69
|
-
getSync(url: string,
|
|
126
|
+
getSync(url: string, options?: RequestOptions): Response;
|
|
70
127
|
|
|
71
128
|
/** Perform a synchronous POST request */
|
|
72
|
-
postSync(
|
|
73
|
-
url: string,
|
|
74
|
-
body?: string | Buffer | Record<string, any>,
|
|
75
|
-
headers?: Record<string, string>
|
|
76
|
-
): Response;
|
|
129
|
+
postSync(url: string, options?: RequestOptions): Response;
|
|
77
130
|
|
|
78
131
|
/** Perform a synchronous custom HTTP request */
|
|
79
|
-
requestSync(
|
|
132
|
+
requestSync(method: string, url: string, options?: RequestOptions): Response;
|
|
80
133
|
|
|
81
134
|
// Promise-based methods
|
|
82
135
|
/** Perform an async GET request */
|
|
83
|
-
get(url: string,
|
|
136
|
+
get(url: string, options?: RequestOptions): Promise<Response>;
|
|
84
137
|
|
|
85
138
|
/** Perform an async POST request */
|
|
86
|
-
post(
|
|
87
|
-
url: string,
|
|
88
|
-
body?: string | Buffer | Record<string, any>,
|
|
89
|
-
headers?: Record<string, string>
|
|
90
|
-
): Promise<Response>;
|
|
139
|
+
post(url: string, options?: RequestOptions): Promise<Response>;
|
|
91
140
|
|
|
92
141
|
/** Perform an async custom HTTP request */
|
|
93
|
-
request(
|
|
142
|
+
request(method: string, url: string, options?: RequestOptions): Promise<Response>;
|
|
94
143
|
|
|
95
144
|
/** Perform an async PUT request */
|
|
96
|
-
put(
|
|
97
|
-
url: string,
|
|
98
|
-
body?: string | Buffer | Record<string, any>,
|
|
99
|
-
headers?: Record<string, string>
|
|
100
|
-
): Promise<Response>;
|
|
145
|
+
put(url: string, options?: RequestOptions): Promise<Response>;
|
|
101
146
|
|
|
102
147
|
/** Perform an async DELETE request */
|
|
103
|
-
delete(url: string,
|
|
148
|
+
delete(url: string, options?: RequestOptions): Promise<Response>;
|
|
104
149
|
|
|
105
150
|
/** Perform an async PATCH request */
|
|
106
|
-
patch(
|
|
107
|
-
url: string,
|
|
108
|
-
body?: string | Buffer | Record<string, any>,
|
|
109
|
-
headers?: Record<string, string>
|
|
110
|
-
): Promise<Response>;
|
|
151
|
+
patch(url: string, options?: RequestOptions): Promise<Response>;
|
|
111
152
|
|
|
112
153
|
/** Perform an async HEAD request */
|
|
113
|
-
head(url: string,
|
|
154
|
+
head(url: string, options?: RequestOptions): Promise<Response>;
|
|
114
155
|
|
|
115
156
|
/** Perform an async OPTIONS request */
|
|
116
|
-
options(url: string,
|
|
157
|
+
options(url: string, options?: RequestOptions): Promise<Response>;
|
|
117
158
|
|
|
118
159
|
// Cookie management
|
|
119
160
|
/** Get all cookies from the session */
|
|
120
161
|
getCookies(): Record<string, string>;
|
|
121
162
|
|
|
163
|
+
/** Get a specific cookie by name */
|
|
164
|
+
getCookie(name: string): string | null;
|
|
165
|
+
|
|
122
166
|
/** Set a cookie in the session */
|
|
123
167
|
setCookie(name: string, value: string): void;
|
|
124
168
|
|
|
169
|
+
/** Delete a specific cookie by name */
|
|
170
|
+
deleteCookie(name: string): void;
|
|
171
|
+
|
|
172
|
+
/** Clear all cookies from the session */
|
|
173
|
+
clearCookies(): void;
|
|
174
|
+
|
|
125
175
|
/** Get cookies as a property */
|
|
126
176
|
readonly cookies: Record<string, string>;
|
|
127
177
|
}
|
|
@@ -162,7 +212,8 @@ export function patch(url: string, options?: RequestOptions): Promise<Response>;
|
|
|
162
212
|
export function head(url: string, options?: RequestOptions): Promise<Response>;
|
|
163
213
|
|
|
164
214
|
/** Perform an OPTIONS request */
|
|
165
|
-
|
|
215
|
+
declare function opts(url: string, options?: RequestOptions): Promise<Response>;
|
|
216
|
+
export { opts as options };
|
|
166
217
|
|
|
167
218
|
/** Perform a custom HTTP request */
|
|
168
219
|
export function request(method: string, url: string, options?: RequestOptions): Promise<Response>;
|
package/lib/index.js
CHANGED
|
@@ -674,7 +674,7 @@ class Session {
|
|
|
674
674
|
* Create a new session
|
|
675
675
|
* @param {Object} options - Session options
|
|
676
676
|
* @param {string} [options.preset="chrome-143"] - Browser preset to use
|
|
677
|
-
* @param {string} [options.proxy] - Proxy URL (e.g., "http://user:pass@host:port")
|
|
677
|
+
* @param {string} [options.proxy] - Proxy URL (e.g., "http://user:pass@host:port" or "socks5://host:port")
|
|
678
678
|
* @param {number} [options.timeout=30] - Request timeout in seconds
|
|
679
679
|
* @param {string} [options.httpVersion="auto"] - HTTP version: "auto", "h1", "h2", "h3"
|
|
680
680
|
* @param {boolean} [options.verify=true] - SSL certificate verification
|
|
@@ -683,6 +683,8 @@ class Session {
|
|
|
683
683
|
* @param {number} [options.retry=3] - Number of retries on failure (set to 0 to disable)
|
|
684
684
|
* @param {number[]} [options.retryOnStatus] - Status codes to retry on
|
|
685
685
|
* @param {Array} [options.auth] - Default auth [username, password] for all requests
|
|
686
|
+
* @param {Object} [options.connectTo] - Domain fronting map {requestHost: connectHost}
|
|
687
|
+
* @param {string} [options.echConfigDomain] - Domain to fetch ECH config from (e.g., "cloudflare-ech.com")
|
|
686
688
|
*/
|
|
687
689
|
constructor(options = {}) {
|
|
688
690
|
const {
|
|
@@ -697,6 +699,8 @@ class Session {
|
|
|
697
699
|
retryOnStatus = null,
|
|
698
700
|
preferIpv4 = false,
|
|
699
701
|
auth = null,
|
|
702
|
+
connectTo = null,
|
|
703
|
+
echConfigDomain = null,
|
|
700
704
|
} = options;
|
|
701
705
|
|
|
702
706
|
this._lib = getLib();
|
|
@@ -727,6 +731,12 @@ class Session {
|
|
|
727
731
|
if (preferIpv4) {
|
|
728
732
|
config.prefer_ipv4 = true;
|
|
729
733
|
}
|
|
734
|
+
if (connectTo) {
|
|
735
|
+
config.connect_to = connectTo;
|
|
736
|
+
}
|
|
737
|
+
if (echConfigDomain) {
|
|
738
|
+
config.ech_config_domain = echConfigDomain;
|
|
739
|
+
}
|
|
730
740
|
|
|
731
741
|
this._handle = this._lib.httpcloak_session_new(JSON.stringify(config));
|
|
732
742
|
|