global-agent 4.1.2 → 4.1.3

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.
Files changed (76) hide show
  1. package/dist/Logger.d.ts +11 -0
  2. package/dist/Logger.js +56 -0
  3. package/dist/classes/Agent.d.ts +46 -0
  4. package/dist/classes/Agent.js +216 -0
  5. package/dist/classes/HttpProxyAgent.d.ts +7 -0
  6. package/dist/classes/HttpProxyAgent.js +20 -0
  7. package/dist/classes/HttpsProxyAgent.d.ts +7 -0
  8. package/dist/classes/HttpsProxyAgent.js +48 -0
  9. package/dist/classes/index.d.ts +3 -0
  10. package/dist/classes/index.js +12 -0
  11. package/dist/errors.d.ts +4 -0
  12. package/dist/errors.js +10 -0
  13. package/dist/factories/createGlobalProxyAgent.d.ts +7 -0
  14. package/dist/factories/createGlobalProxyAgent.js +131 -0
  15. package/dist/factories/createGlobalProxyAgent.test.d.ts +1 -0
  16. package/dist/factories/createGlobalProxyAgent.test.js +539 -0
  17. package/dist/factories/createProxyController.d.ts +7 -0
  18. package/dist/factories/createProxyController.js +38 -0
  19. package/dist/factories/createProxyController.test.d.ts +1 -0
  20. package/dist/factories/createProxyController.test.js +29 -0
  21. package/dist/factories/index.d.ts +2 -0
  22. package/dist/factories/index.js +10 -0
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.js +7 -0
  25. package/dist/routines/bootstrap.d.ts +3 -0
  26. package/dist/routines/bootstrap.js +20 -0
  27. package/dist/routines/index.d.ts +1 -0
  28. package/dist/routines/index.js +8 -0
  29. package/dist/types.d.ts +57 -0
  30. package/dist/types.js +2 -0
  31. package/dist/utilities/bindHttpMethod.d.ts +7 -0
  32. package/dist/utilities/bindHttpMethod.js +50 -0
  33. package/dist/utilities/index.d.ts +3 -0
  34. package/dist/utilities/index.js +12 -0
  35. package/dist/utilities/isUrlMatchingNoProxy.d.ts +2 -0
  36. package/dist/utilities/isUrlMatchingNoProxy.js +27 -0
  37. package/dist/utilities/isUrlMatchingNoProxy.test.d.ts +1 -0
  38. package/dist/utilities/isUrlMatchingNoProxy.test.js +61 -0
  39. package/dist/utilities/parseBoolean.d.ts +1 -0
  40. package/dist/utilities/parseBoolean.js +16 -0
  41. package/dist/utilities/parseProxyUrl.d.ts +6 -0
  42. package/dist/utilities/parseProxyUrl.js +31 -0
  43. package/dist/utilities/parseProxyUrl.test.d.ts +1 -0
  44. package/dist/utilities/parseProxyUrl.test.js +31 -0
  45. package/package.json +5 -2
  46. package/.babelrc +0 -23
  47. package/.editorconfig +0 -9
  48. package/.github/FUNDING.yml +0 -2
  49. package/.github/workflows/feature.yaml +0 -35
  50. package/.github/workflows/main.yaml +0 -50
  51. package/.gitignore +0 -12
  52. package/bootstrap.js +0 -1
  53. package/src/Logger.ts +0 -70
  54. package/src/classes/Agent.ts +0 -296
  55. package/src/classes/HttpProxyAgent.ts +0 -45
  56. package/src/classes/HttpsProxyAgent.ts +0 -83
  57. package/src/classes/index.ts +0 -9
  58. package/src/errors.ts +0 -9
  59. package/src/factories/createGlobalProxyAgent.test.ts +0 -761
  60. package/src/factories/createGlobalProxyAgent.ts +0 -187
  61. package/src/factories/createProxyController.test.ts +0 -38
  62. package/src/factories/createProxyController.ts +0 -51
  63. package/src/factories/index.ts +0 -6
  64. package/src/index.ts +0 -9
  65. package/src/routines/bootstrap.ts +0 -28
  66. package/src/routines/index.ts +0 -3
  67. package/src/types.ts +0 -70
  68. package/src/utilities/bindHttpMethod.ts +0 -53
  69. package/src/utilities/index.ts +0 -9
  70. package/src/utilities/isUrlMatchingNoProxy.test.ts +0 -77
  71. package/src/utilities/isUrlMatchingNoProxy.ts +0 -32
  72. package/src/utilities/parseBoolean.ts +0 -17
  73. package/src/utilities/parseProxyUrl.test.ts +0 -35
  74. package/src/utilities/parseProxyUrl.ts +0 -39
  75. package/tsconfig.json +0 -25
  76. package/vitest.config.ts +0 -11
@@ -0,0 +1,539 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const http_1 = __importDefault(require("http"));
7
+ const https_1 = __importDefault(require("https"));
8
+ const net_1 = __importDefault(require("net"));
9
+ const vitest_1 = require("vitest");
10
+ const axios_1 = __importDefault(require("axios"));
11
+ const get_port_1 = __importDefault(require("get-port"));
12
+ const got_1 = __importDefault(require("got"));
13
+ const pem_1 = __importDefault(require("pem"));
14
+ const request_1 = __importDefault(require("request"));
15
+ const sinon_1 = require("sinon");
16
+ const createGlobalProxyAgent_1 = __importDefault(require("./createGlobalProxyAgent"));
17
+ const defaultHttpAgent = http_1.default.globalAgent;
18
+ const defaultHttpsAgent = https_1.default.globalAgent;
19
+ // Backup original value of NODE_TLS_REJECT_UNAUTHORIZED
20
+ // oxlint-disable-next-line node/no-process-env
21
+ const defaultNodeTlsRejectUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
22
+ let lastPort = 3000;
23
+ let localProxyServers = [];
24
+ let localHttpServers = [];
25
+ let localHttpsServers = [];
26
+ let generatedCerts = null;
27
+ const getNextPort = () => {
28
+ return (0, get_port_1.default)({
29
+ port: get_port_1.default.makeRange(lastPort++, 3500),
30
+ });
31
+ };
32
+ // Generate self-signed certificates for HTTPS testing
33
+ const generateCertificates = () => {
34
+ return new Promise((resolve, reject) => {
35
+ if (generatedCerts) {
36
+ resolve(generatedCerts);
37
+ return;
38
+ }
39
+ pem_1.default.createCertificate({ days: 1, selfSigned: true }, (error, keys) => {
40
+ if (error) {
41
+ reject(error);
42
+ return;
43
+ }
44
+ generatedCerts = { cert: keys.certificate, key: keys.serviceKey };
45
+ resolve(generatedCerts);
46
+ });
47
+ });
48
+ };
49
+ (0, vitest_1.beforeAll)(async () => {
50
+ // Pre-generate certificates
51
+ await generateCertificates();
52
+ });
53
+ (0, vitest_1.beforeEach)(() => {
54
+ http_1.default.globalAgent = defaultHttpAgent;
55
+ https_1.default.globalAgent = defaultHttpsAgent;
56
+ });
57
+ (0, vitest_1.afterEach)(() => {
58
+ for (const localProxyServer of localProxyServers) {
59
+ localProxyServer.stop();
60
+ }
61
+ localProxyServers = [];
62
+ for (const localHttpServer of localHttpServers) {
63
+ localHttpServer.stop();
64
+ }
65
+ localHttpServers = [];
66
+ for (const localHttpsServer of localHttpsServers) {
67
+ localHttpsServer.stop();
68
+ }
69
+ localHttpsServers = [];
70
+ // Reset NODE_TLS_REJECT_UNAUTHORIZED to original value
71
+ // oxlint-disable-next-line node/no-process-env
72
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = defaultNodeTlsRejectUnauthorized;
73
+ });
74
+ const createHttpResponseResolver = (resolve) => {
75
+ return (response) => {
76
+ let body = '';
77
+ response.on('data', (data) => {
78
+ body += data;
79
+ });
80
+ response.on('end', () => {
81
+ if (!response.headers) {
82
+ throw new Error('response.headers is not defined');
83
+ }
84
+ if (!response.statusCode) {
85
+ throw new Error('response.statusCode is not defined');
86
+ }
87
+ resolve({
88
+ body,
89
+ headers: response.headers,
90
+ statusCode: response.statusCode,
91
+ });
92
+ });
93
+ };
94
+ };
95
+ // Create a local HTTPS server for CONNECT tunnel targets
96
+ const createHttpsServer = async () => {
97
+ const port = await getNextPort();
98
+ const certs = await generateCertificates();
99
+ const localHttpsServer = await new Promise((resolve) => {
100
+ const httpsServer = https_1.default.createServer({
101
+ cert: certs.cert,
102
+ key: certs.key,
103
+ }, (request, response) => {
104
+ response.writeHead(200, { 'content-type': 'text/plain' });
105
+ response.end('OK');
106
+ });
107
+ httpsServer.listen(port, '127.0.0.1', () => {
108
+ resolve({
109
+ port,
110
+ stop: () => {
111
+ httpsServer.close();
112
+ },
113
+ url: 'https://127.0.0.1:' + port,
114
+ });
115
+ });
116
+ });
117
+ localHttpsServers.push(localHttpsServer);
118
+ return localHttpsServer;
119
+ };
120
+ // Create a simple HTTP proxy server that can handle both HTTP requests and HTTPS CONNECT tunneling
121
+ const createProxyServer = async (rules) => {
122
+ const port = await getNextPort();
123
+ // Create an HTTPS server that the proxy will tunnel to for CONNECT requests
124
+ const httpsServer = await createHttpsServer();
125
+ const localProxyServer = await new Promise((resolve) => {
126
+ const proxyServer = http_1.default.createServer((request, response) => {
127
+ // Handle regular HTTP proxy requests
128
+ if (rules === null || rules === void 0 ? void 0 : rules.beforeSendRequest) {
129
+ const result = rules.beforeSendRequest({
130
+ requestOptions: {
131
+ headers: request.headers,
132
+ },
133
+ });
134
+ response.writeHead(result.response.statusCode, result.response.header);
135
+ response.end(result.response.body);
136
+ }
137
+ else {
138
+ // Default response
139
+ response.writeHead(200, { 'content-type': 'text/plain' });
140
+ response.end('OK');
141
+ }
142
+ });
143
+ // Handle CONNECT requests for HTTPS tunneling
144
+ proxyServer.on('connect', (request, clientSocket, head) => {
145
+ // Call onConnect hook if provided
146
+ if (rules === null || rules === void 0 ? void 0 : rules.onConnect) {
147
+ rules.onConnect(request);
148
+ }
149
+ // Connect to the local HTTPS server instead of the requested host
150
+ const serverSocket = net_1.default.connect(httpsServer.port, '127.0.0.1', () => {
151
+ clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
152
+ serverSocket.write(head);
153
+ serverSocket.pipe(clientSocket);
154
+ clientSocket.pipe(serverSocket);
155
+ });
156
+ serverSocket.on('error', () => {
157
+ clientSocket.end('HTTP/1.1 500 Internal Server Error\r\n\r\n');
158
+ });
159
+ clientSocket.on('error', () => {
160
+ serverSocket.end();
161
+ });
162
+ });
163
+ proxyServer.listen(port, () => {
164
+ resolve({
165
+ httpsServer,
166
+ port,
167
+ stop: () => {
168
+ proxyServer.close();
169
+ },
170
+ url: 'http://127.0.0.1:' + port,
171
+ });
172
+ });
173
+ });
174
+ localProxyServers.push(localProxyServer);
175
+ return localProxyServer;
176
+ };
177
+ const createHttpServer = async () => {
178
+ const port = await getNextPort();
179
+ const localHttpServer = await new Promise((resolve) => {
180
+ const httpServer = http_1.default.createServer((request, response) => {
181
+ response.end('DIRECT');
182
+ });
183
+ httpServer.listen(port, () => {
184
+ resolve({
185
+ stop: () => {
186
+ httpServer.close();
187
+ },
188
+ url: 'http://127.0.0.1:' + port,
189
+ });
190
+ });
191
+ });
192
+ localHttpServers.push(localHttpServer);
193
+ return localHttpServer;
194
+ };
195
+ (0, vitest_1.test)('proxies HTTP request', async () => {
196
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
197
+ const proxyServer = await createProxyServer();
198
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
199
+ const response = await new Promise((resolve) => {
200
+ http_1.default.get('http://127.0.0.1', createHttpResponseResolver(resolve));
201
+ });
202
+ (0, vitest_1.expect)(response.body).toBe('OK');
203
+ });
204
+ (0, vitest_1.test)('proxies HTTP request with proxy-authorization header', async () => {
205
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
206
+ const beforeSendRequest = (0, sinon_1.stub)().callsFake(() => {
207
+ return {
208
+ response: {
209
+ body: 'OK',
210
+ header: { 'content-type': 'text/plain' },
211
+ statusCode: 200,
212
+ },
213
+ };
214
+ });
215
+ const proxyServer = await createProxyServer({
216
+ beforeSendRequest,
217
+ });
218
+ globalProxyAgent.HTTP_PROXY = 'http://foo@127.0.0.1:' + proxyServer.port;
219
+ const response = await new Promise((resolve) => {
220
+ http_1.default.get('http://127.0.0.1', createHttpResponseResolver(resolve));
221
+ });
222
+ (0, vitest_1.expect)(response.body).toBe('OK');
223
+ (0, vitest_1.expect)(beforeSendRequest.firstCall.args[0].requestOptions.headers['proxy-authorization']).toBe('Basic Zm9v');
224
+ });
225
+ (0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = undefined', async () => {
226
+ // oxlint-disable-next-line node/no-process-env
227
+ const { NODE_TLS_REJECT_UNAUTHORIZED, ...restEnvironments } = process.env; // oxlint-disable-line @typescript-eslint/no-unused-vars
228
+ // oxlint-disable-next-line node/no-process-env
229
+ process.env = restEnvironments;
230
+ // oxlint-disable-next-line node/no-process-env
231
+ process.env.GLOBAL_AGENT_FORCE_GLOBAL_AGENT = 'true';
232
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
233
+ const proxyServer = await createProxyServer();
234
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
235
+ const globalAgent = https_1.default.globalAgent;
236
+ (0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(true);
237
+ const response = await new Promise((resolve) => {
238
+ http_1.default.get('http://127.0.0.1', createHttpResponseResolver(resolve));
239
+ });
240
+ (0, vitest_1.expect)(response.body).toBe('OK');
241
+ });
242
+ (0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = null', async () => {
243
+ // oxlint-disable-next-line node/no-process-env
244
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = 'null';
245
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
246
+ const proxyServer = await createProxyServer();
247
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
248
+ const globalAgent = https_1.default.globalAgent;
249
+ (0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(false);
250
+ });
251
+ (0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = 1', async () => {
252
+ // @ts-expect-error it is expected as we wanted to set process variable with int
253
+ // oxlint-disable-next-line node/no-process-env
254
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
255
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
256
+ const proxyServer = await createProxyServer();
257
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
258
+ const globalAgent = https_1.default.globalAgent;
259
+ (0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(true);
260
+ });
261
+ (0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = 0', async () => {
262
+ // @ts-expect-error it is expected as we wanted to set process variable with int
263
+ // oxlint-disable-next-line node/no-process-env
264
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
265
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
266
+ const proxyServer = await createProxyServer();
267
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
268
+ const globalAgent = https_1.default.globalAgent;
269
+ (0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(false);
270
+ });
271
+ (0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = true', async () => {
272
+ // @ts-expect-error it is expected as we wanted to set process variable with boolean
273
+ // oxlint-disable-next-line node/no-process-env
274
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = true;
275
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
276
+ const proxyServer = await createProxyServer();
277
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
278
+ const globalAgent = https_1.default.globalAgent;
279
+ (0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(true);
280
+ });
281
+ (0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = false', async () => {
282
+ // @ts-expect-error it is expected as we wanted to set process variable with boolean
283
+ // oxlint-disable-next-line node/no-process-env
284
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = false;
285
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
286
+ const proxyServer = await createProxyServer();
287
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
288
+ const globalAgent = https_1.default.globalAgent;
289
+ (0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(false);
290
+ });
291
+ (0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = yes', async () => {
292
+ // oxlint-disable-next-line node/no-process-env
293
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = 'yes';
294
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
295
+ const proxyServer = await createProxyServer();
296
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
297
+ const globalAgent = https_1.default.globalAgent;
298
+ (0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(true);
299
+ });
300
+ (0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = no', async () => {
301
+ // oxlint-disable-next-line node/no-process-env
302
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = 'no';
303
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
304
+ const proxyServer = await createProxyServer();
305
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
306
+ const globalAgent = https_1.default.globalAgent;
307
+ (0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(false);
308
+ });
309
+ (0, vitest_1.test)('Test addCACertificates and clearCACertificates methods', async () => {
310
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
311
+ const proxyServer = await createProxyServer();
312
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
313
+ const globalAgent = https_1.default.globalAgent;
314
+ (0, vitest_1.expect)(globalAgent.ca).toBe(undefined);
315
+ globalAgent.addCACertificates(['test-ca-certficate1', 'test-ca-certficate2']);
316
+ globalAgent.addCACertificates(['test-ca-certficate3']);
317
+ const result = ['test-ca-certficate1', 'test-ca-certficate2', 'test-ca-certficate3'];
318
+ (0, vitest_1.expect)(globalAgent.ca.length).toBe(result.length);
319
+ (0, vitest_1.expect)(JSON.stringify(globalAgent.ca)).toBe(JSON.stringify(result));
320
+ globalAgent.clearCACertificates();
321
+ (0, vitest_1.expect)(globalAgent.ca).toBe(undefined);
322
+ });
323
+ (0, vitest_1.test)('Test addCACertificates when passed ca is a string', async () => {
324
+ // oxlint-disable-next-line node/no-process-env
325
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
326
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
327
+ const proxyServer = await createProxyServer();
328
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
329
+ const globalAgent = https_1.default.globalAgent;
330
+ (0, vitest_1.expect)(globalAgent.ca).toBe(undefined);
331
+ globalAgent.addCACertificates('test-ca-certficate1');
332
+ globalAgent.addCACertificates('test-ca-certficate2');
333
+ (0, vitest_1.expect)(globalAgent.ca).toBe('test-ca-certficate1test-ca-certficate2');
334
+ const response = await new Promise((resolve) => {
335
+ https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
336
+ });
337
+ (0, vitest_1.expect)(response.body).toBe('OK');
338
+ });
339
+ (0, vitest_1.test)('Test addCACertificates when input ca is a string and existing ca is array', async () => {
340
+ // oxlint-disable-next-line node/no-process-env
341
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
342
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)({ ca: ['test-ca'] });
343
+ const proxyServer = await createProxyServer();
344
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
345
+ const globalAgent = https_1.default.globalAgent;
346
+ (0, vitest_1.expect)(globalAgent.ca.length).toBe(1);
347
+ globalAgent.addCACertificates('test-ca-certficate1');
348
+ (0, vitest_1.expect)(globalAgent.ca.length).toBe(1);
349
+ (0, vitest_1.expect)(JSON.stringify(globalAgent.ca)).toBe(JSON.stringify(['test-ca']));
350
+ const response = await new Promise((resolve) => {
351
+ https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
352
+ });
353
+ (0, vitest_1.expect)(response.body).toBe('OK');
354
+ });
355
+ (0, vitest_1.test)('Test addCACertificates when input ca array is null or undefined', async () => {
356
+ // oxlint-disable-next-line node/no-process-env
357
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
358
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
359
+ const proxyServer = await createProxyServer();
360
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
361
+ const globalAgent = https_1.default.globalAgent;
362
+ (0, vitest_1.expect)(globalAgent.ca).toBe(undefined);
363
+ globalAgent.addCACertificates(undefined);
364
+ globalAgent.addCACertificates(null);
365
+ (0, vitest_1.expect)(globalAgent.ca).toBe(undefined);
366
+ const response = await new Promise((resolve) => {
367
+ https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
368
+ });
369
+ (0, vitest_1.expect)(response.body).toBe('OK');
370
+ });
371
+ (0, vitest_1.test)('Test initializing ca certificate property while creating global proxy agent', async () => {
372
+ // oxlint-disable-next-line node/no-process-env
373
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
374
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)({ ca: ['test-ca'] });
375
+ const proxyServer = await createProxyServer();
376
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
377
+ const globalAgent = https_1.default.globalAgent;
378
+ (0, vitest_1.expect)(globalAgent.ca.length).toBe(1);
379
+ globalAgent.addCACertificates(['test-ca1']);
380
+ (0, vitest_1.expect)(globalAgent.ca.length).toBe(2);
381
+ (0, vitest_1.expect)(globalAgent.ca[0]).toBe('test-ca');
382
+ (0, vitest_1.expect)(globalAgent.ca[1]).toBe('test-ca1');
383
+ const response = await new Promise((resolve) => {
384
+ https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
385
+ });
386
+ (0, vitest_1.expect)(response.body).toBe('OK');
387
+ });
388
+ (0, vitest_1.test)('proxies HTTPS request', async () => {
389
+ // oxlint-disable-next-line node/no-process-env
390
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
391
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
392
+ const proxyServer = await createProxyServer();
393
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
394
+ const response = await new Promise((resolve) => {
395
+ https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
396
+ });
397
+ (0, vitest_1.expect)(response.body).toBe('OK');
398
+ });
399
+ (0, vitest_1.test)('proxies HTTPS request with proxy-authorization header', async () => {
400
+ // oxlint-disable-next-line node/no-process-env
401
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
402
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
403
+ const onConnect = (0, sinon_1.stub)();
404
+ const proxyServer = await createProxyServer({
405
+ onConnect,
406
+ });
407
+ globalProxyAgent.HTTP_PROXY = 'http://foo@127.0.0.1:' + proxyServer.port;
408
+ const response = await new Promise((resolve) => {
409
+ https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
410
+ });
411
+ (0, vitest_1.expect)(response.body).toBe('OK');
412
+ (0, vitest_1.expect)(onConnect.firstCall.args[0].headers['proxy-authorization']).toBe('Basic Zm9v');
413
+ });
414
+ (0, vitest_1.test)('does not produce unhandled rejection when cannot connect to proxy', async () => {
415
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
416
+ const port = await getNextPort();
417
+ globalProxyAgent.HTTP_PROXY = 'http://127.0.0.1:' + port;
418
+ await (0, vitest_1.expect)((0, got_1.default)('http://127.0.0.1')).rejects.toThrow();
419
+ });
420
+ (0, vitest_1.test)('proxies HTTPS request with dedicated proxy', async () => {
421
+ // oxlint-disable-next-line node/no-process-env
422
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
423
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
424
+ const proxyServer = await createProxyServer();
425
+ globalProxyAgent.HTTPS_PROXY = proxyServer.url;
426
+ const response = await new Promise((resolve) => {
427
+ https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
428
+ });
429
+ (0, vitest_1.expect)(response.body).toBe('OK');
430
+ });
431
+ (0, vitest_1.test)('ignores dedicated HTTPS proxy for HTTP urls', async () => {
432
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
433
+ const proxyServer = await createProxyServer();
434
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
435
+ globalProxyAgent.HTTPS_PROXY = 'http://example.org';
436
+ const response = await new Promise((resolve) => {
437
+ http_1.default.get('http://127.0.0.1', {}, createHttpResponseResolver(resolve));
438
+ });
439
+ (0, vitest_1.expect)(response.body).toBe('OK');
440
+ });
441
+ (0, vitest_1.test)('forwards requests matching NO_PROXY', async () => {
442
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
443
+ const proxyServer = await createProxyServer();
444
+ const httpServer = await createHttpServer();
445
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
446
+ globalProxyAgent.NO_PROXY = '127.0.0.1';
447
+ const response = await new Promise((resolve) => {
448
+ http_1.default.get(httpServer.url, createHttpResponseResolver(resolve));
449
+ });
450
+ (0, vitest_1.expect)(response.body).toBe('DIRECT');
451
+ });
452
+ (0, vitest_1.test)('forwards requests that go to a socket', async () => {
453
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
454
+ // not relevant as traffic shouldn't go through proxy
455
+ globalProxyAgent.HTTP_PROXY = 'localhost:10324';
456
+ const server = http_1.default.createServer((request, serverResponse) => {
457
+ serverResponse.writeHead(200);
458
+ serverResponse.write('OK');
459
+ serverResponse.end();
460
+ });
461
+ server.listen('/tmp/test.sock');
462
+ const response = await new Promise((resolve) => {
463
+ http_1.default.get({
464
+ path: '/endpoint',
465
+ socketPath: '/tmp/test.sock',
466
+ }, createHttpResponseResolver(resolve));
467
+ });
468
+ server.close();
469
+ (0, vitest_1.expect)(response.body).toBe('OK');
470
+ });
471
+ (0, vitest_1.test)('proxies HTTP request (using http.get(host))', async () => {
472
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
473
+ const proxyServer = await createProxyServer();
474
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
475
+ const response = await new Promise((resolve) => {
476
+ http_1.default.get({
477
+ host: '127.0.0.1',
478
+ }, createHttpResponseResolver(resolve));
479
+ });
480
+ (0, vitest_1.expect)(response.body).toBe('OK');
481
+ });
482
+ (0, vitest_1.test)('proxies HTTP request (using got)', async () => {
483
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
484
+ const proxyServer = await createProxyServer();
485
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
486
+ const response = await (0, got_1.default)('http://127.0.0.1');
487
+ (0, vitest_1.expect)(response.body).toBe('OK');
488
+ });
489
+ (0, vitest_1.test)('proxies HTTPS request (using got)', async () => {
490
+ // oxlint-disable-next-line node/no-process-env
491
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
492
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
493
+ const proxyServer = await createProxyServer();
494
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
495
+ const response = await (0, got_1.default)('https://127.0.0.1');
496
+ (0, vitest_1.expect)(response.body).toBe('OK');
497
+ });
498
+ (0, vitest_1.test)('proxies HTTP request (using axios)', async () => {
499
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
500
+ const proxyServer = await createProxyServer();
501
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
502
+ const response = await axios_1.default.get('http://127.0.0.1');
503
+ (0, vitest_1.expect)(response.data).toBe('OK');
504
+ });
505
+ (0, vitest_1.test)('proxies HTTPS request (using axios)', async () => {
506
+ // oxlint-disable-next-line node/no-process-env
507
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
508
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
509
+ const proxyServer = await createProxyServer();
510
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
511
+ const response = await axios_1.default.get('https://127.0.0.1');
512
+ (0, vitest_1.expect)(response.data).toBe('OK');
513
+ });
514
+ (0, vitest_1.test)('proxies HTTP request (using request)', async () => {
515
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
516
+ const proxyServer = await createProxyServer();
517
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
518
+ const response = await new Promise((resolve) => {
519
+ (0, request_1.default)('http://127.0.0.1', (error, requestResponse, body) => {
520
+ (0, vitest_1.expect)(error).toBe(null);
521
+ resolve(body);
522
+ });
523
+ });
524
+ (0, vitest_1.expect)(response).toBe('OK');
525
+ });
526
+ (0, vitest_1.test)('proxies HTTPS request (using request)', async () => {
527
+ // oxlint-disable-next-line node/no-process-env
528
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
529
+ const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
530
+ const proxyServer = await createProxyServer();
531
+ globalProxyAgent.HTTP_PROXY = proxyServer.url;
532
+ const response = await new Promise((resolve) => {
533
+ (0, request_1.default)('https://127.0.0.1', (error, requestResponse, body) => {
534
+ (0, vitest_1.expect)(error).toBe(null);
535
+ resolve(body);
536
+ });
537
+ });
538
+ (0, vitest_1.expect)(response).toBe('OK');
539
+ });
@@ -0,0 +1,7 @@
1
+ type ProxyController = {
2
+ HTTP_PROXY: string | null;
3
+ HTTPS_PROXY: string | null;
4
+ NO_PROXY: string | null;
5
+ };
6
+ declare const _default: () => ProxyController;
7
+ export default _default;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const Logger_1 = require("../Logger");
4
+ const log = Logger_1.logger.child({
5
+ namespace: 'createProxyController',
6
+ });
7
+ const KNOWN_PROPERTY_NAMES = [
8
+ 'HTTP_PROXY',
9
+ 'HTTPS_PROXY',
10
+ 'NO_PROXY',
11
+ ];
12
+ exports.default = () => {
13
+ // oxlint-disable-next-line fp/no-proxy
14
+ return new Proxy({
15
+ HTTP_PROXY: null,
16
+ HTTPS_PROXY: null,
17
+ NO_PROXY: null,
18
+ }, {
19
+ set: (subject, name, value) => {
20
+ if (typeof name !== 'string') {
21
+ throw new TypeError('Unexpected object member.');
22
+ }
23
+ if (!KNOWN_PROPERTY_NAMES.includes(name)) {
24
+ throw new Error('Cannot set an unmapped property "' + name + '".');
25
+ }
26
+ // @ts-expect-error string cannot be used to index an object
27
+ subject[name] = value;
28
+ log.info({
29
+ change: {
30
+ name,
31
+ value,
32
+ },
33
+ newConfiguration: subject,
34
+ }, 'configuration changed');
35
+ return true;
36
+ },
37
+ });
38
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const vitest_1 = require("vitest");
7
+ const createProxyController_1 = __importDefault(require("./createProxyController"));
8
+ (0, vitest_1.test)('sets HTTP_PROXY', () => {
9
+ const globalAgentGlobal = (0, createProxyController_1.default)();
10
+ globalAgentGlobal.HTTP_PROXY = 'http://127.0.0.1';
11
+ (0, vitest_1.expect)(globalAgentGlobal.HTTP_PROXY).toBe('http://127.0.0.1');
12
+ });
13
+ (0, vitest_1.test)('sets HTTPS_PROXY', () => {
14
+ const globalAgentGlobal = (0, createProxyController_1.default)();
15
+ globalAgentGlobal.HTTPS_PROXY = 'http://127.0.0.1';
16
+ (0, vitest_1.expect)(globalAgentGlobal.HTTPS_PROXY).toBe('http://127.0.0.1');
17
+ });
18
+ (0, vitest_1.test)('sets NO_PROXY', () => {
19
+ const globalAgentGlobal = (0, createProxyController_1.default)();
20
+ globalAgentGlobal.NO_PROXY = '*';
21
+ (0, vitest_1.expect)(globalAgentGlobal.NO_PROXY).toBe('*');
22
+ });
23
+ (0, vitest_1.test)('throws an error if unknown property is set', () => {
24
+ const globalAgentGlobal = (0, createProxyController_1.default)();
25
+ (0, vitest_1.expect)(() => {
26
+ // @ts-expect-error expected unknown property.
27
+ globalAgentGlobal.FOO = 'BAR';
28
+ }).toThrow('Cannot set an unmapped property "FOO".');
29
+ });
@@ -0,0 +1,2 @@
1
+ export { default as createGlobalProxyAgent, } from './createGlobalProxyAgent';
2
+ export { default as createProxyController, } from './createProxyController';
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createProxyController = exports.createGlobalProxyAgent = void 0;
7
+ var createGlobalProxyAgent_1 = require("./createGlobalProxyAgent");
8
+ Object.defineProperty(exports, "createGlobalProxyAgent", { enumerable: true, get: function () { return __importDefault(createGlobalProxyAgent_1).default; } });
9
+ var createProxyController_1 = require("./createProxyController");
10
+ Object.defineProperty(exports, "createProxyController", { enumerable: true, get: function () { return __importDefault(createProxyController_1).default; } });
@@ -0,0 +1,3 @@
1
+ export { bootstrap, } from './routines';
2
+ export { createGlobalProxyAgent, } from './factories';
3
+ export type { Logger, } from './Logger';
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createGlobalProxyAgent = exports.bootstrap = void 0;
4
+ var routines_1 = require("./routines");
5
+ Object.defineProperty(exports, "bootstrap", { enumerable: true, get: function () { return routines_1.bootstrap; } });
6
+ var factories_1 = require("./factories");
7
+ Object.defineProperty(exports, "createGlobalProxyAgent", { enumerable: true, get: function () { return factories_1.createGlobalProxyAgent; } });
@@ -0,0 +1,3 @@
1
+ import type { ProxyAgentConfigurationInputType } from '../types';
2
+ declare const _default: (configurationInput?: ProxyAgentConfigurationInputType) => boolean;
3
+ export default _default;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const globalthis_1 = __importDefault(require("globalthis"));
7
+ const Logger_1 = require("../Logger");
8
+ const factories_1 = require("../factories");
9
+ const globalThis = (0, globalthis_1.default)();
10
+ const log = Logger_1.logger.child({
11
+ namespace: 'bootstrap',
12
+ });
13
+ exports.default = (configurationInput) => {
14
+ if (globalThis.GLOBAL_AGENT) {
15
+ log.warn('found globalThis.GLOBAL_AGENT; second attempt to bootstrap global-agent was ignored');
16
+ return false;
17
+ }
18
+ globalThis.GLOBAL_AGENT = (0, factories_1.createGlobalProxyAgent)(configurationInput);
19
+ return true;
20
+ };