global-agent 3.0.0 → 4.0.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/.babelrc +23 -0
- package/.editorconfig +9 -0
- package/.eslintignore +1 -0
- package/.eslintrc +27 -0
- package/.github/FUNDING.yml +2 -0
- package/.github/workflows/feature.yaml +32 -0
- package/.github/workflows/main.yaml +31 -0
- package/.gitignore +14 -0
- package/LICENSE +2 -2
- package/README.md +67 -8
- package/package.json +48 -56
- package/src/{Logger.js → Logger.ts} +3 -3
- package/{dist/classes/Agent.js.flow → src/classes/Agent.ts} +121 -39
- package/src/classes/HttpProxyAgent.ts +45 -0
- package/src/classes/HttpsProxyAgent.ts +83 -0
- package/src/classes/index.ts +9 -0
- package/src/{errors.js → errors.ts} +2 -6
- package/src/factories/{createGlobalProxyAgent.js → createGlobalProxyAgent.ts} +36 -50
- package/{dist/factories/createProxyController.js.flow → src/factories/createProxyController.ts} +8 -5
- package/src/factories/index.ts +6 -0
- package/src/index.ts +6 -0
- package/{dist/routines/bootstrap.js.flow → src/routines/bootstrap.ts} +6 -5
- package/src/routines/index.ts +3 -0
- package/src/types.ts +66 -0
- package/src/utilities/{bindHttpMethod.js → bindHttpMethod.ts} +6 -7
- package/src/utilities/index.ts +9 -0
- package/{dist/utilities/isUrlMatchingNoProxy.js.flow → src/utilities/isUrlMatchingNoProxy.ts} +1 -6
- package/src/utilities/parseBoolean.ts +17 -0
- package/src/utilities/{parseProxyUrl.js → parseProxyUrl.ts} +12 -9
- package/test/.eslintrc +10 -0
- package/test/global-agent/factories/createGlobalProxyAgent.ts +760 -0
- package/test/global-agent/factories/createProxyController.ts +37 -0
- package/test/global-agent/utilities/isUrlMatchingNoProxy.ts +62 -0
- package/test/global-agent/utilities/parseProxyUrl.ts +38 -0
- package/tsconfig.json +25 -0
- package/.flowconfig +0 -3
- package/dist/Logger.js +0 -18
- package/dist/Logger.js.flow +0 -10
- package/dist/Logger.js.map +0 -1
- package/dist/classes/Agent.js +0 -174
- package/dist/classes/Agent.js.map +0 -1
- package/dist/classes/HttpProxyAgent.js +0 -33
- package/dist/classes/HttpProxyAgent.js.flow +0 -30
- package/dist/classes/HttpProxyAgent.js.map +0 -1
- package/dist/classes/HttpsProxyAgent.js +0 -53
- package/dist/classes/HttpsProxyAgent.js.flow +0 -54
- package/dist/classes/HttpsProxyAgent.js.map +0 -1
- package/dist/classes/index.js +0 -32
- package/dist/classes/index.js.flow +0 -5
- package/dist/classes/index.js.map +0 -1
- package/dist/errors.js +0 -22
- package/dist/errors.js.flow +0 -15
- package/dist/errors.js.map +0 -1
- package/dist/factories/createGlobalProxyAgent.js +0 -175
- package/dist/factories/createGlobalProxyAgent.js.flow +0 -197
- package/dist/factories/createGlobalProxyAgent.js.map +0 -1
- package/dist/factories/createProxyController.js +0 -45
- package/dist/factories/createProxyController.js.map +0 -1
- package/dist/factories/index.js +0 -24
- package/dist/factories/index.js.flow +0 -4
- package/dist/factories/index.js.map +0 -1
- package/dist/index.js +0 -22
- package/dist/index.js.flow +0 -4
- package/dist/index.js.map +0 -1
- package/dist/routines/bootstrap.js +0 -30
- package/dist/routines/bootstrap.js.map +0 -1
- package/dist/routines/index.js +0 -16
- package/dist/routines/index.js.flow +0 -3
- package/dist/routines/index.js.map +0 -1
- package/dist/types.js +0 -10
- package/dist/types.js.flow +0 -66
- package/dist/types.js.map +0 -1
- package/dist/utilities/bindHttpMethod.js +0 -62
- package/dist/utilities/bindHttpMethod.js.flow +0 -54
- package/dist/utilities/bindHttpMethod.js.map +0 -1
- package/dist/utilities/index.js +0 -32
- package/dist/utilities/index.js.flow +0 -5
- package/dist/utilities/index.js.map +0 -1
- package/dist/utilities/isUrlMatchingNoProxy.js +0 -43
- package/dist/utilities/isUrlMatchingNoProxy.js.map +0 -1
- package/dist/utilities/parseProxyUrl.js +0 -42
- package/dist/utilities/parseProxyUrl.js.flow +0 -36
- package/dist/utilities/parseProxyUrl.js.map +0 -1
- package/src/classes/Agent.js +0 -212
- package/src/classes/HttpProxyAgent.js +0 -30
- package/src/classes/HttpsProxyAgent.js +0 -54
- package/src/classes/index.js +0 -5
- package/src/factories/createProxyController.js +0 -46
- package/src/factories/index.js +0 -4
- package/src/index.js +0 -4
- package/src/routines/bootstrap.js +0 -25
- package/src/routines/index.js +0 -3
- package/src/types.js +0 -66
- package/src/utilities/index.js +0 -5
- package/src/utilities/isUrlMatchingNoProxy.js +0 -37
|
@@ -0,0 +1,760 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IncomingMessage,
|
|
3
|
+
IncomingHttpHeaders,
|
|
4
|
+
} from 'http';
|
|
5
|
+
import http from 'http';
|
|
6
|
+
import https from 'https';
|
|
7
|
+
import net from 'net';
|
|
8
|
+
import {
|
|
9
|
+
serial,
|
|
10
|
+
before,
|
|
11
|
+
afterEach,
|
|
12
|
+
beforeEach,
|
|
13
|
+
} from 'ava';
|
|
14
|
+
import axios from 'axios';
|
|
15
|
+
import getPort from 'get-port';
|
|
16
|
+
import got from 'got';
|
|
17
|
+
import pem from 'pem';
|
|
18
|
+
import makeRequest from 'request';
|
|
19
|
+
import {
|
|
20
|
+
stub,
|
|
21
|
+
} from 'sinon';
|
|
22
|
+
import createGlobalProxyAgent from '../../../src/factories/createGlobalProxyAgent';
|
|
23
|
+
|
|
24
|
+
type ProxyServerType = {
|
|
25
|
+
port: number,
|
|
26
|
+
stop: () => void,
|
|
27
|
+
url: string,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type HttpServerType = {
|
|
31
|
+
stop: () => void,
|
|
32
|
+
url: string,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
type HttpsServerType = {
|
|
36
|
+
port: number,
|
|
37
|
+
stop: () => void,
|
|
38
|
+
url: string,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
type ProxyRules = {
|
|
42
|
+
beforeSendRequest?: (requestDetail: {
|
|
43
|
+
requestOptions: {
|
|
44
|
+
headers: Record<string, string>,
|
|
45
|
+
},
|
|
46
|
+
}) => {
|
|
47
|
+
response: {
|
|
48
|
+
body: string,
|
|
49
|
+
header: Record<string, string>,
|
|
50
|
+
statusCode: number,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
onConnect?: (request: http.IncomingMessage) => void,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const defaultHttpAgent = http.globalAgent;
|
|
57
|
+
const defaultHttpsAgent = https.globalAgent;
|
|
58
|
+
|
|
59
|
+
// Backup original value of NODE_TLS_REJECT_UNAUTHORIZED
|
|
60
|
+
// eslint-disable-next-line node/no-process-env
|
|
61
|
+
const defaultNodeTlsRejectUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
|
|
62
|
+
|
|
63
|
+
let lastPort = 3_000;
|
|
64
|
+
|
|
65
|
+
let localProxyServers: ProxyServerType[] = [];
|
|
66
|
+
let localHttpServers: HttpServerType[] = [];
|
|
67
|
+
let localHttpsServers: HttpsServerType[] = [];
|
|
68
|
+
let generatedCerts: {
|
|
69
|
+
cert: string,
|
|
70
|
+
key: string,
|
|
71
|
+
} | null = null;
|
|
72
|
+
|
|
73
|
+
const getNextPort = (): Promise<number> => {
|
|
74
|
+
return getPort({
|
|
75
|
+
port: getPort.makeRange(lastPort++, 3_500),
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Generate self-signed certificates for HTTPS testing
|
|
80
|
+
const generateCertificates = (): Promise<{
|
|
81
|
+
cert: string,
|
|
82
|
+
key: string,
|
|
83
|
+
}> => {
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
if (generatedCerts) {
|
|
86
|
+
resolve(generatedCerts);
|
|
87
|
+
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
pem.createCertificate({days: 1, selfSigned: true}, (error, keys) => {
|
|
92
|
+
if (error) {
|
|
93
|
+
reject(error);
|
|
94
|
+
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
generatedCerts = {cert: keys.certificate, key: keys.serviceKey};
|
|
99
|
+
resolve(generatedCerts);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
before(async () => {
|
|
105
|
+
// Pre-generate certificates
|
|
106
|
+
await generateCertificates();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
beforeEach(() => {
|
|
110
|
+
http.globalAgent = defaultHttpAgent;
|
|
111
|
+
https.globalAgent = defaultHttpsAgent;
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
afterEach(() => {
|
|
115
|
+
for (const localProxyServer of localProxyServers) {
|
|
116
|
+
localProxyServer.stop();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
localProxyServers = [];
|
|
120
|
+
|
|
121
|
+
for (const localHttpServer of localHttpServers) {
|
|
122
|
+
localHttpServer.stop();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
localHttpServers = [];
|
|
126
|
+
|
|
127
|
+
for (const localHttpsServer of localHttpsServers) {
|
|
128
|
+
localHttpsServer.stop();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
localHttpsServers = [];
|
|
132
|
+
|
|
133
|
+
// Reset NODE_TLS_REJECT_UNAUTHORIZED to original value
|
|
134
|
+
// eslint-disable-next-line node/no-process-env
|
|
135
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = defaultNodeTlsRejectUnauthorized;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
type HttpResponseType = {
|
|
139
|
+
body: string,
|
|
140
|
+
headers: IncomingHttpHeaders,
|
|
141
|
+
statusCode: number,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const createHttpResponseResolver = (resolve: (response: HttpResponseType) => void) => {
|
|
145
|
+
return (response: IncomingMessage) => {
|
|
146
|
+
let body = '';
|
|
147
|
+
|
|
148
|
+
response.on('data', (data) => {
|
|
149
|
+
body += data;
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
response.on('end', () => {
|
|
153
|
+
if (!response.headers) {
|
|
154
|
+
throw new Error('response.headers is not defined');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!response.statusCode) {
|
|
158
|
+
throw new Error('response.statusCode is not defined');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
resolve({
|
|
162
|
+
body,
|
|
163
|
+
headers: response.headers,
|
|
164
|
+
statusCode: response.statusCode,
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// Create a local HTTPS server for CONNECT tunnel targets
|
|
171
|
+
const createHttpsServer = async (): Promise<HttpsServerType> => {
|
|
172
|
+
const port = await getNextPort();
|
|
173
|
+
const certs = await generateCertificates();
|
|
174
|
+
|
|
175
|
+
const localHttpsServer: HttpsServerType = await new Promise((resolve) => {
|
|
176
|
+
const httpsServer = https.createServer({
|
|
177
|
+
cert: certs.cert,
|
|
178
|
+
key: certs.key,
|
|
179
|
+
}, (request, response) => {
|
|
180
|
+
response.writeHead(200, {'content-type': 'text/plain'});
|
|
181
|
+
response.end('OK');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
httpsServer.listen(port, '127.0.0.1', () => {
|
|
185
|
+
resolve({
|
|
186
|
+
port,
|
|
187
|
+
stop: () => {
|
|
188
|
+
httpsServer.close();
|
|
189
|
+
},
|
|
190
|
+
url: 'https://127.0.0.1:' + port,
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
localHttpsServers.push(localHttpsServer);
|
|
196
|
+
|
|
197
|
+
return localHttpsServer;
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Create a simple HTTP proxy server that can handle both HTTP requests and HTTPS CONNECT tunneling
|
|
201
|
+
const createProxyServer = async (rules?: ProxyRules): Promise<ProxyServerType & {
|
|
202
|
+
httpsServer?: HttpsServerType,
|
|
203
|
+
}> => {
|
|
204
|
+
const port = await getNextPort();
|
|
205
|
+
|
|
206
|
+
// Create an HTTPS server that the proxy will tunnel to for CONNECT requests
|
|
207
|
+
const httpsServer = await createHttpsServer();
|
|
208
|
+
|
|
209
|
+
const localProxyServer: ProxyServerType & {
|
|
210
|
+
httpsServer?: HttpsServerType,
|
|
211
|
+
} = await new Promise((resolve) => {
|
|
212
|
+
const proxyServer = http.createServer((request, response) => {
|
|
213
|
+
// Handle regular HTTP proxy requests
|
|
214
|
+
if (rules?.beforeSendRequest) {
|
|
215
|
+
const result = rules.beforeSendRequest({
|
|
216
|
+
requestOptions: {
|
|
217
|
+
headers: request.headers as Record<string, string>,
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
response.writeHead(result.response.statusCode, result.response.header);
|
|
222
|
+
response.end(result.response.body);
|
|
223
|
+
} else {
|
|
224
|
+
// Default response
|
|
225
|
+
response.writeHead(200, {'content-type': 'text/plain'});
|
|
226
|
+
response.end('OK');
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Handle CONNECT requests for HTTPS tunneling
|
|
231
|
+
proxyServer.on('connect', (request, clientSocket, head) => {
|
|
232
|
+
// Call onConnect hook if provided
|
|
233
|
+
if (rules?.onConnect) {
|
|
234
|
+
rules.onConnect(request);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Connect to the local HTTPS server instead of the requested host
|
|
238
|
+
const serverSocket = net.connect(httpsServer.port, '127.0.0.1', () => {
|
|
239
|
+
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
|
|
240
|
+
serverSocket.write(head);
|
|
241
|
+
serverSocket.pipe(clientSocket);
|
|
242
|
+
clientSocket.pipe(serverSocket);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
serverSocket.on('error', () => {
|
|
246
|
+
clientSocket.end('HTTP/1.1 500 Internal Server Error\r\n\r\n');
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
clientSocket.on('error', () => {
|
|
250
|
+
serverSocket.end();
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
proxyServer.listen(port, () => {
|
|
255
|
+
resolve({
|
|
256
|
+
httpsServer,
|
|
257
|
+
port,
|
|
258
|
+
stop: () => {
|
|
259
|
+
proxyServer.close();
|
|
260
|
+
},
|
|
261
|
+
url: 'http://127.0.0.1:' + port,
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
localProxyServers.push(localProxyServer);
|
|
267
|
+
|
|
268
|
+
return localProxyServer;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const createHttpServer = async (): Promise<HttpServerType> => {
|
|
272
|
+
const port = await getNextPort();
|
|
273
|
+
|
|
274
|
+
const localHttpServer: HttpServerType = await new Promise((resolve) => {
|
|
275
|
+
const httpServer = http.createServer((request, response) => {
|
|
276
|
+
response.end('DIRECT');
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
httpServer.listen(port, () => {
|
|
280
|
+
resolve({
|
|
281
|
+
stop: () => {
|
|
282
|
+
httpServer.close();
|
|
283
|
+
},
|
|
284
|
+
url: 'http://127.0.0.1:' + port,
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
localHttpServers.push(localHttpServer);
|
|
290
|
+
|
|
291
|
+
return localHttpServer;
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
serial('proxies HTTP request', async (t) => {
|
|
295
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
296
|
+
|
|
297
|
+
const proxyServer = await createProxyServer();
|
|
298
|
+
|
|
299
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
300
|
+
|
|
301
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
302
|
+
http.get('http://127.0.0.1', createHttpResponseResolver(resolve));
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
t.is(response.body, 'OK');
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
serial('proxies HTTP request with proxy-authorization header', async (t) => {
|
|
309
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
310
|
+
|
|
311
|
+
const beforeSendRequest = stub().callsFake(() => {
|
|
312
|
+
return {
|
|
313
|
+
response: {
|
|
314
|
+
body: 'OK',
|
|
315
|
+
header: {'content-type': 'text/plain'},
|
|
316
|
+
statusCode: 200,
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
const proxyServer = await createProxyServer({
|
|
322
|
+
beforeSendRequest,
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
globalProxyAgent.HTTP_PROXY = 'http://foo@127.0.0.1:' + proxyServer.port;
|
|
326
|
+
|
|
327
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
328
|
+
http.get('http://127.0.0.1', createHttpResponseResolver(resolve));
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
t.is(response.body, 'OK');
|
|
332
|
+
|
|
333
|
+
t.is(beforeSendRequest.firstCall.args[0].requestOptions.headers['proxy-authorization'], 'Basic Zm9v');
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
serial('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = undefined', async (t) => {
|
|
337
|
+
// eslint-disable-next-line node/no-process-env
|
|
338
|
+
const {NODE_TLS_REJECT_UNAUTHORIZED, ...restEnvironments} = process.env; // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
339
|
+
// eslint-disable-next-line node/no-process-env
|
|
340
|
+
process.env = restEnvironments;
|
|
341
|
+
// eslint-disable-next-line node/no-process-env
|
|
342
|
+
process.env.GLOBAL_AGENT_FORCE_GLOBAL_AGENT = 'true';
|
|
343
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
344
|
+
const proxyServer = await createProxyServer();
|
|
345
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
346
|
+
const globalAgent: any = https.globalAgent;
|
|
347
|
+
t.is(globalAgent.getRejectUnauthorized(), true);
|
|
348
|
+
|
|
349
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
350
|
+
http.get('http://127.0.0.1', createHttpResponseResolver(resolve));
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
t.is(response.body, 'OK');
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
serial('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = null', async (t) => {
|
|
357
|
+
// eslint-disable-next-line node/no-process-env
|
|
358
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 'null';
|
|
359
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
360
|
+
const proxyServer = await createProxyServer();
|
|
361
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
362
|
+
|
|
363
|
+
const globalAgent: any = https.globalAgent;
|
|
364
|
+
t.is(globalAgent.getRejectUnauthorized(), false);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
serial('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = 1', async (t) => {
|
|
368
|
+
// @ts-expect-error it is expected as we wanted to set process variable with int
|
|
369
|
+
// eslint-disable-next-line node/no-process-env
|
|
370
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
|
|
371
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
372
|
+
|
|
373
|
+
const proxyServer = await createProxyServer();
|
|
374
|
+
|
|
375
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
376
|
+
|
|
377
|
+
const globalAgent: any = https.globalAgent;
|
|
378
|
+
t.is(globalAgent.getRejectUnauthorized(), true);
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
serial('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = 0', async (t) => {
|
|
382
|
+
// @ts-expect-error it is expected as we wanted to set process variable with int
|
|
383
|
+
// eslint-disable-next-line node/no-process-env
|
|
384
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
|
|
385
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
386
|
+
|
|
387
|
+
const proxyServer = await createProxyServer();
|
|
388
|
+
|
|
389
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
390
|
+
|
|
391
|
+
const globalAgent: any = https.globalAgent;
|
|
392
|
+
t.is(globalAgent.getRejectUnauthorized(), false);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
serial('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = true', async (t) => {
|
|
396
|
+
// @ts-expect-error it is expected as we wanted to set process variable with boolean
|
|
397
|
+
// eslint-disable-next-line node/no-process-env
|
|
398
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = true;
|
|
399
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
400
|
+
const proxyServer = await createProxyServer();
|
|
401
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
402
|
+
|
|
403
|
+
const globalAgent: any = https.globalAgent;
|
|
404
|
+
t.is(globalAgent.getRejectUnauthorized(), true);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
serial('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = false', async (t) => {
|
|
408
|
+
// @ts-expect-error it is expected as we wanted to set process variable with boolean
|
|
409
|
+
// eslint-disable-next-line node/no-process-env
|
|
410
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = false;
|
|
411
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
412
|
+
const proxyServer = await createProxyServer();
|
|
413
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
414
|
+
|
|
415
|
+
const globalAgent: any = https.globalAgent;
|
|
416
|
+
t.is(globalAgent.getRejectUnauthorized(), false);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
serial('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = yes', async (t) => {
|
|
420
|
+
// eslint-disable-next-line node/no-process-env
|
|
421
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 'yes';
|
|
422
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
423
|
+
const proxyServer = await createProxyServer();
|
|
424
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
425
|
+
|
|
426
|
+
const globalAgent: any = https.globalAgent;
|
|
427
|
+
t.is(globalAgent.getRejectUnauthorized(), true);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
serial('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = no', async (t) => {
|
|
431
|
+
// eslint-disable-next-line node/no-process-env
|
|
432
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 'no';
|
|
433
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
434
|
+
const proxyServer = await createProxyServer();
|
|
435
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
436
|
+
|
|
437
|
+
const globalAgent: any = https.globalAgent;
|
|
438
|
+
t.is(globalAgent.getRejectUnauthorized(), false);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
serial('Test addCACertificates and clearCACertificates methods', async (t) => {
|
|
442
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
443
|
+
|
|
444
|
+
const proxyServer = await createProxyServer();
|
|
445
|
+
|
|
446
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
447
|
+
const globalAgent: any = https.globalAgent;
|
|
448
|
+
t.is(globalAgent.ca, undefined);
|
|
449
|
+
globalAgent.addCACertificates(['test-ca-certficate1', 'test-ca-certficate2']);
|
|
450
|
+
globalAgent.addCACertificates(['test-ca-certficate3']);
|
|
451
|
+
const result = ['test-ca-certficate1', 'test-ca-certficate2', 'test-ca-certficate3'];
|
|
452
|
+
t.is(globalAgent.ca.length, result.length);
|
|
453
|
+
t.is(JSON.stringify(globalAgent.ca), JSON.stringify(result));
|
|
454
|
+
globalAgent.clearCACertificates();
|
|
455
|
+
t.is(globalAgent.ca, undefined);
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
serial('Test addCACertificates when passed ca is a string', async (t) => {
|
|
459
|
+
// eslint-disable-next-line node/no-process-env
|
|
460
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
461
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
462
|
+
|
|
463
|
+
const proxyServer = await createProxyServer();
|
|
464
|
+
|
|
465
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
466
|
+
const globalAgent: any = https.globalAgent;
|
|
467
|
+
t.is(globalAgent.ca, undefined);
|
|
468
|
+
globalAgent.addCACertificates('test-ca-certficate1');
|
|
469
|
+
globalAgent.addCACertificates('test-ca-certficate2');
|
|
470
|
+
t.is(globalAgent.ca, 'test-ca-certficate1test-ca-certficate2');
|
|
471
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
472
|
+
https.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
|
473
|
+
});
|
|
474
|
+
t.is(response.body, 'OK');
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
serial('Test addCACertificates when input ca is a string and existing ca is array', async (t) => {
|
|
478
|
+
// eslint-disable-next-line node/no-process-env
|
|
479
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
480
|
+
const globalProxyAgent = createGlobalProxyAgent({ca: ['test-ca']});
|
|
481
|
+
|
|
482
|
+
const proxyServer = await createProxyServer();
|
|
483
|
+
|
|
484
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
485
|
+
const globalAgent: any = https.globalAgent;
|
|
486
|
+
t.is(globalAgent.ca.length, 1);
|
|
487
|
+
globalAgent.addCACertificates('test-ca-certficate1');
|
|
488
|
+
t.is(globalAgent.ca.length, 1);
|
|
489
|
+
t.is(JSON.stringify(globalAgent.ca), JSON.stringify(['test-ca']));
|
|
490
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
491
|
+
https.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
|
492
|
+
});
|
|
493
|
+
t.is(response.body, 'OK');
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
serial('Test addCACertificates when input ca array is null or undefined', async (t) => {
|
|
497
|
+
// eslint-disable-next-line node/no-process-env
|
|
498
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
499
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
500
|
+
|
|
501
|
+
const proxyServer = await createProxyServer();
|
|
502
|
+
|
|
503
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
504
|
+
const globalAgent: any = https.globalAgent;
|
|
505
|
+
t.is(globalAgent.ca, undefined);
|
|
506
|
+
globalAgent.addCACertificates(undefined);
|
|
507
|
+
globalAgent.addCACertificates(null);
|
|
508
|
+
t.is(globalAgent.ca, undefined);
|
|
509
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
510
|
+
https.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
|
511
|
+
});
|
|
512
|
+
t.is(response.body, 'OK');
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
serial('Test initializing ca certificate property while creating global proxy agent', async (t) => {
|
|
516
|
+
// eslint-disable-next-line node/no-process-env
|
|
517
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
518
|
+
const globalProxyAgent = createGlobalProxyAgent({ca: ['test-ca']});
|
|
519
|
+
|
|
520
|
+
const proxyServer = await createProxyServer();
|
|
521
|
+
|
|
522
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
523
|
+
const globalAgent: any = https.globalAgent;
|
|
524
|
+
t.is(globalAgent.ca.length, 1);
|
|
525
|
+
globalAgent.addCACertificates(['test-ca1']);
|
|
526
|
+
t.is(globalAgent.ca.length, 2);
|
|
527
|
+
t.is(globalAgent.ca[0], 'test-ca');
|
|
528
|
+
t.is(globalAgent.ca[1], 'test-ca1');
|
|
529
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
530
|
+
https.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
|
531
|
+
});
|
|
532
|
+
t.is(response.body, 'OK');
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
serial('proxies HTTPS request', async (t) => {
|
|
536
|
+
// eslint-disable-next-line node/no-process-env
|
|
537
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
538
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
539
|
+
|
|
540
|
+
const proxyServer = await createProxyServer();
|
|
541
|
+
|
|
542
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
543
|
+
|
|
544
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
545
|
+
https.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
t.is(response.body, 'OK');
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
serial('proxies HTTPS request with proxy-authorization header', async (t) => {
|
|
552
|
+
// eslint-disable-next-line node/no-process-env
|
|
553
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
554
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
555
|
+
|
|
556
|
+
const onConnect = stub();
|
|
557
|
+
|
|
558
|
+
const proxyServer = await createProxyServer({
|
|
559
|
+
onConnect,
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
globalProxyAgent.HTTP_PROXY = 'http://foo@127.0.0.1:' + proxyServer.port;
|
|
563
|
+
|
|
564
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
565
|
+
https.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
t.is(response.body, 'OK');
|
|
569
|
+
|
|
570
|
+
t.is(onConnect.firstCall.args[0].headers['proxy-authorization'], 'Basic Zm9v');
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
serial('does not produce unhandled rejection when cannot connect to proxy', async (t) => {
|
|
574
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
575
|
+
|
|
576
|
+
const port = await getNextPort();
|
|
577
|
+
|
|
578
|
+
globalProxyAgent.HTTP_PROXY = 'http://127.0.0.1:' + port;
|
|
579
|
+
|
|
580
|
+
await t.throwsAsync(got('http://127.0.0.1'));
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
serial('proxies HTTPS request with dedicated proxy', async (t) => {
|
|
584
|
+
// eslint-disable-next-line node/no-process-env
|
|
585
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
586
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
587
|
+
|
|
588
|
+
const proxyServer = await createProxyServer();
|
|
589
|
+
|
|
590
|
+
globalProxyAgent.HTTPS_PROXY = proxyServer.url;
|
|
591
|
+
|
|
592
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
593
|
+
https.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
t.is(response.body, 'OK');
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
serial('ignores dedicated HTTPS proxy for HTTP urls', async (t) => {
|
|
600
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
601
|
+
|
|
602
|
+
const proxyServer = await createProxyServer();
|
|
603
|
+
|
|
604
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
605
|
+
globalProxyAgent.HTTPS_PROXY = 'http://example.org';
|
|
606
|
+
|
|
607
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
608
|
+
http.get('http://127.0.0.1', {}, createHttpResponseResolver(resolve));
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
t.is(response.body, 'OK');
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
serial('forwards requests matching NO_PROXY', async (t) => {
|
|
615
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
616
|
+
|
|
617
|
+
const proxyServer = await createProxyServer();
|
|
618
|
+
const httpServer = await createHttpServer();
|
|
619
|
+
|
|
620
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
621
|
+
globalProxyAgent.NO_PROXY = '127.0.0.1';
|
|
622
|
+
|
|
623
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
624
|
+
http.get(httpServer.url, createHttpResponseResolver(resolve));
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
t.is(response.body, 'DIRECT');
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
serial('forwards requests that go to a socket', async (t) => {
|
|
631
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
632
|
+
|
|
633
|
+
// not relevant as traffic shouldn't go through proxy
|
|
634
|
+
globalProxyAgent.HTTP_PROXY = 'localhost:10324';
|
|
635
|
+
|
|
636
|
+
const server = http.createServer((request, serverResponse) => {
|
|
637
|
+
serverResponse.writeHead(200);
|
|
638
|
+
serverResponse.write('OK');
|
|
639
|
+
serverResponse.end();
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
t.teardown(() => {
|
|
643
|
+
server.close();
|
|
644
|
+
});
|
|
645
|
+
server.listen('/tmp/test.sock');
|
|
646
|
+
|
|
647
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
648
|
+
http.get({
|
|
649
|
+
path: '/endpoint',
|
|
650
|
+
socketPath: '/tmp/test.sock',
|
|
651
|
+
}, createHttpResponseResolver(resolve));
|
|
652
|
+
});
|
|
653
|
+
t.is(response.body, 'OK');
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
serial('proxies HTTP request (using http.get(host))', async (t) => {
|
|
657
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
658
|
+
|
|
659
|
+
const proxyServer = await createProxyServer();
|
|
660
|
+
|
|
661
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
662
|
+
|
|
663
|
+
const response: HttpResponseType = await new Promise((resolve) => {
|
|
664
|
+
http.get({
|
|
665
|
+
host: '127.0.0.1',
|
|
666
|
+
}, createHttpResponseResolver(resolve));
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
t.is(response.body, 'OK');
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
serial('proxies HTTP request (using got)', async (t) => {
|
|
673
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
674
|
+
|
|
675
|
+
const proxyServer = await createProxyServer();
|
|
676
|
+
|
|
677
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
678
|
+
|
|
679
|
+
const response = await got('http://127.0.0.1');
|
|
680
|
+
|
|
681
|
+
t.is(response.body, 'OK');
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
serial('proxies HTTPS request (using got)', async (t) => {
|
|
685
|
+
// eslint-disable-next-line node/no-process-env
|
|
686
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
687
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
688
|
+
|
|
689
|
+
const proxyServer = await createProxyServer();
|
|
690
|
+
|
|
691
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
692
|
+
|
|
693
|
+
const response = await got('https://127.0.0.1');
|
|
694
|
+
|
|
695
|
+
t.is(response.body, 'OK');
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
serial('proxies HTTP request (using axios)', async (t) => {
|
|
699
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
700
|
+
|
|
701
|
+
const proxyServer = await createProxyServer();
|
|
702
|
+
|
|
703
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
704
|
+
|
|
705
|
+
const response = await axios.get('http://127.0.0.1');
|
|
706
|
+
|
|
707
|
+
t.is(response.data, 'OK');
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
serial('proxies HTTPS request (using axios)', async (t) => {
|
|
711
|
+
// eslint-disable-next-line node/no-process-env
|
|
712
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
713
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
714
|
+
|
|
715
|
+
const proxyServer = await createProxyServer();
|
|
716
|
+
|
|
717
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
718
|
+
|
|
719
|
+
const response = await axios.get('https://127.0.0.1');
|
|
720
|
+
|
|
721
|
+
t.is(response.data, 'OK');
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
serial('proxies HTTP request (using request)', async (t) => {
|
|
725
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
726
|
+
|
|
727
|
+
const proxyServer = await createProxyServer();
|
|
728
|
+
|
|
729
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
730
|
+
|
|
731
|
+
const response = await new Promise((resolve) => {
|
|
732
|
+
makeRequest('http://127.0.0.1', (error, requestResponse, body) => {
|
|
733
|
+
t.is(error, null);
|
|
734
|
+
|
|
735
|
+
resolve(body);
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
t.is(response, 'OK');
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
serial('proxies HTTPS request (using request)', async (t) => {
|
|
743
|
+
// eslint-disable-next-line node/no-process-env
|
|
744
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
745
|
+
const globalProxyAgent = createGlobalProxyAgent();
|
|
746
|
+
|
|
747
|
+
const proxyServer = await createProxyServer();
|
|
748
|
+
|
|
749
|
+
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
|
750
|
+
|
|
751
|
+
const response = await new Promise((resolve) => {
|
|
752
|
+
makeRequest('https://127.0.0.1', (error, requestResponse, body) => {
|
|
753
|
+
t.is(error, null);
|
|
754
|
+
|
|
755
|
+
resolve(body);
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
t.is(response, 'OK');
|
|
760
|
+
});
|