docs: add quixzoom-auth-core product to AAMOS
- Product documentation in docs/products/ - Updated MEMORY.md with product info - quiXzoom Auth Core as AAMOS Identity product
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2026, Gajus Kuizinas (https://gajus.com/)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Gajus Kuizinas (https://gajus.com/) nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL ANUARY BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+316
@@ -0,0 +1,316 @@
|
||||
# global-agent
|
||||
|
||||
[](https://www.npmjs.org/package/global-agent)
|
||||
[](https://github.com/gajus/canonical)
|
||||
[](https://twitter.com/kuizinas)
|
||||
|
||||
Global HTTP/HTTPS proxy configurable using environment variables.
|
||||
|
||||
* [Usage](#usage)
|
||||
* [Setup proxy using `global-agent/bootstrap`](#setup-proxy-using-global-agentbootstrap)
|
||||
* [Setup proxy using `bootstrap` routine](#setup-proxy-using-bootstrap-routine)
|
||||
* [Runtime configuration](#runtime-configuration)
|
||||
* [Exclude URLs](#exclude-urls)
|
||||
* [API](#api)
|
||||
* [`createGlobalProxyAgent`](#createglobalproxyagent)
|
||||
* [Environment variables](#environment-variables)
|
||||
* [`global.GLOBAL_AGENT`](#globalglobal_agent)
|
||||
* [Supported libraries](#supported-libraries)
|
||||
* [FAQ](#faq)
|
||||
* [What is the reason `global-agent` overrides explicitly configured HTTP(S) agent?](#what-is-the-reason-global-agent-overrides-explicitly-configured-https-agent)
|
||||
* [What is the reason `global-agent/bootstrap` does not use `HTTP_PROXY`?](#what-is-the-reason-global-agentbootstrap-does-not-use-http_proxy)
|
||||
* [What is the difference from `global-tunnel` and `tunnel`?](#what-is-the-difference-from-global-tunnel-and-tunnel)
|
||||
|
||||
## Usage
|
||||
|
||||
### Setup proxy using `global-agent/bootstrap`
|
||||
|
||||
To configure HTTP proxy:
|
||||
|
||||
1. Import `global-agent/bootstrap`.
|
||||
1. Export HTTP proxy address as `GLOBAL_AGENT_HTTP_PROXY` environment variable.
|
||||
|
||||
Code:
|
||||
|
||||
```js
|
||||
import 'global-agent/bootstrap';
|
||||
|
||||
// or:
|
||||
// import {bootstrap} from 'global-agent';
|
||||
// bootstrap();
|
||||
|
||||
```
|
||||
|
||||
Bash:
|
||||
|
||||
```bash
|
||||
$ export GLOBAL_AGENT_HTTP_PROXY=http://127.0.0.1:8080
|
||||
|
||||
```
|
||||
|
||||
Alternatively, you can preload module using Node.js `--require, -r` configuration, e.g.
|
||||
|
||||
```bash
|
||||
$ export GLOBAL_AGENT_HTTP_PROXY=http://127.0.0.1:8080
|
||||
$ node -r 'global-agent/bootstrap' your-script.js
|
||||
|
||||
```
|
||||
|
||||
### Setup proxy using `bootstrap` routine
|
||||
|
||||
Instead of importing a self-initialising script with side-effects as demonstrated in the [setup proxy using `global-agent/bootstrap`](#setup-proxy-using-global-agentbootstrap) documentation, you can import `bootstrap` routine and explicitly evaluate the bootstrap logic, e.g.
|
||||
|
||||
```js
|
||||
import {
|
||||
bootstrap
|
||||
} from 'global-agent';
|
||||
|
||||
bootstrap();
|
||||
|
||||
```
|
||||
|
||||
This is useful if you need to conditionally bootstrap `global-agent`, e.g.
|
||||
|
||||
```js
|
||||
import {
|
||||
bootstrap
|
||||
} from 'global-agent';
|
||||
import globalTunnel from 'global-tunnel-ng';
|
||||
|
||||
const MAJOR_NODEJS_VERSION = parseInt(process.version.slice(1).split('.')[0], 10);
|
||||
|
||||
if (MAJOR_NODEJS_VERSION >= 10) {
|
||||
// `global-agent` works with Node.js v10 and above.
|
||||
bootstrap();
|
||||
} else {
|
||||
// `global-tunnel-ng` works only with Node.js v10 and below.
|
||||
globalTunnel.initialize();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Setup proxy using `createGlobalProxyAgent`
|
||||
|
||||
If you do not want to use `global.GLOBAL_AGENT` variable, then you can use `createGlobalProxyAgent` to instantiate a controlled instance of `global-agent`, e.g.
|
||||
|
||||
```js
|
||||
import {
|
||||
createGlobalProxyAgent
|
||||
} from 'global-agent';
|
||||
|
||||
const globalProxyAgent = createGlobalProxyAgent();
|
||||
|
||||
```
|
||||
|
||||
Unlike `bootstrap` routine, `createGlobalProxyAgent` factory does not create `global.GLOBAL_AGENT` variable and does not guard against multiple initializations of `global-agent`. The result object of `createGlobalProxyAgent` is equivalent to `global.GLOBAL_AGENT`.
|
||||
|
||||
### Runtime configuration
|
||||
|
||||
`global-agent/bootstrap` script copies `process.env.GLOBAL_AGENT_HTTP_PROXY` value to `global.GLOBAL_AGENT.HTTP_PROXY` and continues to use the latter variable.
|
||||
|
||||
You can override the `global.GLOBAL_AGENT.HTTP_PROXY` value at runtime to change proxy behaviour, e.g.
|
||||
|
||||
```js
|
||||
http.get('http://127.0.0.1:8000');
|
||||
|
||||
global.GLOBAL_AGENT.HTTP_PROXY = 'http://127.0.0.1:8001';
|
||||
|
||||
http.get('http://127.0.0.1:8000');
|
||||
|
||||
global.GLOBAL_AGENT.HTTP_PROXY = 'http://127.0.0.1:8002';
|
||||
|
||||
```
|
||||
|
||||
The first HTTP request is going to use http://127.0.0.1:8001 proxy and the second request is going to use http://127.0.0.1:8002.
|
||||
|
||||
All `global-agent` configuration is available under `global.GLOBAL_AGENT` namespace.
|
||||
|
||||
### Exclude URLs
|
||||
|
||||
The `GLOBAL_AGENT_NO_PROXY` environment variable specifies a pattern of URLs that should be excluded from proxying. `GLOBAL_AGENT_NO_PROXY` value is a comma-separated list of domain names. Asterisks can be used as wildcards, e.g.
|
||||
|
||||
```bash
|
||||
export GLOBAL_AGENT_NO_PROXY='*.foo.com,baz.com'
|
||||
|
||||
```
|
||||
|
||||
says to contact all machines with the 'foo.com' TLD and 'baz.com' domains directly.
|
||||
|
||||
### Separate proxy for HTTPS
|
||||
|
||||
The environment variable `GLOBAL_AGENT_HTTPS_PROXY` can be set to specify a separate proxy for HTTPS requests. When this variable is not set `GLOBAL_AGENT_HTTP_PROXY` is used for both HTTP and HTTPS requests.
|
||||
|
||||
## API
|
||||
|
||||
### `createGlobalProxyAgent`
|
||||
|
||||
```js
|
||||
/**
|
||||
* @property environmentVariableNamespace Defines namespace of `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` environment variables. (Default: `GLOBAL_AGENT_`)
|
||||
* @property forceGlobalAgent Forces to use `global-agent` HTTP(S) agent even when request was explicitly constructed with another agent. (Default: `true`)
|
||||
* @property socketConnectionTimeout Destroys socket if connection is not established within the timeout. (Default: `60000`)
|
||||
* @property ca Single CA certificate or an array of CA certificates that is trusted for secure connections to the registry.
|
||||
* @property logger Custom logger instance for debug logging. Must implement `child`, `debug`, `error`, `info`, `trace`, and `warn` methods.
|
||||
*/
|
||||
type ProxyAgentConfigurationInputType = {|
|
||||
+environmentVariableNamespace?: string,
|
||||
+forceGlobalAgent?: boolean,
|
||||
+socketConnectionTimeout?: number,
|
||||
+ca?: string[] | string,
|
||||
+logger?: Logger,
|
||||
|};
|
||||
|
||||
(configurationInput: ProxyAgentConfigurationInputType) => ProxyAgentConfigurationType;
|
||||
|
||||
```
|
||||
|
||||
### Custom Logger
|
||||
|
||||
You can provide a custom logger to `global-agent` for debugging purposes. The logger must implement the following interface:
|
||||
|
||||
```ts
|
||||
type Logger = {
|
||||
child: (context: object) => Logger,
|
||||
debug: (context: object | string, message?: string) => void,
|
||||
error: (context: object | string, message?: string) => void,
|
||||
info: (context: object | string, message?: string) => void,
|
||||
trace: (context: object | string, message?: string) => void,
|
||||
warn: (context: object | string, message?: string) => void,
|
||||
};
|
||||
```
|
||||
|
||||
Example using a custom logger:
|
||||
|
||||
```js
|
||||
import { createGlobalProxyAgent } from 'global-agent';
|
||||
|
||||
createGlobalProxyAgent({
|
||||
logger: {
|
||||
child: () => logger,
|
||||
debug: console.debug,
|
||||
error: console.error,
|
||||
info: console.info,
|
||||
trace: console.trace,
|
||||
warn: console.warn,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
|Name|Description|Default|
|
||||
|---|---|---|
|
||||
|`GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE`|Defines namespace of `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` environment variables.|`GLOBAL_AGENT_`|
|
||||
|`GLOBAL_AGENT_FORCE_GLOBAL_AGENT`|Forces to use `global-agent` HTTP(S) agent even when request was explicitly constructed with another agent.|`true`|
|
||||
|`GLOBAL_AGENT_SOCKET_CONNECTION_TIMEOUT`|Destroys socket if connection is not established within the timeout.|`60000`|
|
||||
|`${NAMESPACE}HTTP_PROXY`|Sets the initial proxy controller HTTP_PROXY value.|N/A|
|
||||
|`${NAMESPACE}HTTPS_PROXY`|Sets the initial proxy controller HTTPS_PROXY value.|N/A|
|
||||
|`${NAMESPACE}NO_PROXY`|Sets the initial proxy controller NO_PROXY value.|N/A|
|
||||
|
||||
### `global.GLOBAL_AGENT`
|
||||
|
||||
`global.GLOBAL_AGENT` is initialized by `bootstrap` routine.
|
||||
|
||||
`global.GLOBAL_AGENT` has the following properties:
|
||||
|
||||
|Name|Configurable|Description|
|
||||
|---|---|---|
|
||||
|`HTTP_PROXY`|Yes|Sets HTTP proxy to use.|
|
||||
|`HTTPS_PROXY`|Yes|Sets a distinct proxy to use for HTTPS requests.|
|
||||
|`NO_PROXY`|Yes|Specifies a pattern of URLs that should be excluded from proxying. See [Exclude URLs](#exclude-urls).|
|
||||
|
||||
## Certificate Authority (CA)
|
||||
|
||||
### `addCACertificates`
|
||||
This method can be accessed using https to add CA certificates to the global-agent.
|
||||
|
||||
Uses:
|
||||
```js
|
||||
if (typeof https.globalAgent.addCACertificates === 'function') {
|
||||
//certificate - an array of ca certificates to be added to the global-agent
|
||||
https.globalAgent.addCACertificates(certificate);
|
||||
}
|
||||
```
|
||||
|
||||
Method Definition:
|
||||
```js
|
||||
/**
|
||||
* This method can be used to append new ca certificates to existing ca certificates
|
||||
* @param {string[] | string} ca a ca certificate or an array of ca certificates
|
||||
*/
|
||||
public addCACertificates (ca: string[] | string) {
|
||||
if (!ca) {
|
||||
log.error('Invalid input ca certificate');
|
||||
} else if (this.ca) {
|
||||
if (typeof ca === typeof this.ca) {
|
||||
// concat valid ca certificates with the existing certificates,
|
||||
if (typeof this.ca === 'string') {
|
||||
this.ca = this.ca.concat(ca as string);
|
||||
} else {
|
||||
this.ca = this.ca.concat(ca as string[]);
|
||||
}
|
||||
} else {
|
||||
log.error('Input ca certificate type mismatched with existing ca certificate type');
|
||||
}
|
||||
} else {
|
||||
this.ca = ca;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `clearCACertificates`
|
||||
This method can be accessed using https to clear existing CA certificates from global-agent.
|
||||
|
||||
Uses:
|
||||
```js
|
||||
if (typeof https.globalAgent.clearCACertificates === 'function') {
|
||||
https.globalAgent.clearCACertificates();
|
||||
}
|
||||
```
|
||||
Method Definition:
|
||||
```js
|
||||
/**
|
||||
* This method clears existing CA Certificates.
|
||||
* It sets ca to undefined
|
||||
*/
|
||||
public clearCACertificates () {
|
||||
this.ca = undefined;
|
||||
}
|
||||
```
|
||||
|
||||
## Supported libraries
|
||||
|
||||
`global-agent` works with all libraries that internally use [`http.request`](https://nodejs.org/api/http.html#http_http_request_options_callback).
|
||||
|
||||
`global-agent` has been tested to work with:
|
||||
|
||||
* [`got`](https://www.npmjs.com/package/got)
|
||||
* [`axios`](https://www.npmjs.com/package/axios)
|
||||
* [`request`](https://www.npmjs.com/package/request)
|
||||
|
||||
## FAQ
|
||||
|
||||
### What is the reason `global-agent` overrides explicitly configured HTTP(S) agent?
|
||||
|
||||
By default, `global-agent` overrides [`agent` property](https://nodejs.org/api/http.html#http_http_request_options_callback) of any HTTP request, even if `agent` property was explicitly set when constructing a HTTP request. This behaviour allows to intercept requests of libraries that use a custom instance of an agent per default (e.g. Stripe SDK [uses an `http(s).globalAgent` instance pre-configured with `keepAlive: true`](https://github.com/stripe/stripe-node/blob/e542902dd8fbe591fe3c3ce07a7e89d1d60e4cf7/lib/StripeResource.js#L11-L12)).
|
||||
|
||||
This behaviour can be disabled with `GLOBAL_AGENT_FORCE_GLOBAL_AGENT=false` environment variable. When disabled, then `global-agent` will only set `agent` property when it is not already defined or if `agent` is an instance of `http(s).globalAgent`.
|
||||
|
||||
### What is the reason `global-agent/bootstrap` does not use `HTTP_PROXY`?
|
||||
|
||||
Some libraries (e.g. [`request`](https://npmjs.org/package/request)) change their behaviour when `HTTP_PROXY` environment variable is present. Using a namespaced environment variable prevents conflicting library behaviour.
|
||||
|
||||
You can override this behaviour by configuring `GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE` variable, e.g.
|
||||
|
||||
```bash
|
||||
$ export GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE=
|
||||
|
||||
```
|
||||
|
||||
Now script initialized using `global-agent/bootstrap` will use `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` environment variables.
|
||||
|
||||
### What is the difference from `global-tunnel` and `tunnel`?
|
||||
|
||||
[`global-tunnel`](https://github.com/salesforce/global-tunnel) (including [`global-tunnel-ng`](https://github.com/np-maintain/global-tunnel) and [`tunnel`](https://npmjs.com/package/tunnel)) are designed to support legacy Node.js versions. They use various [workarounds](https://github.com/koichik/node-tunnel/blob/5fb2fb424788597146b7be6729006cad1cf9e9a8/lib/tunnel.js#L134-L144) and rely on [monkey-patching `http.request`, `http.get`, `https.request` and `https.get` methods](https://github.com/np-maintain/global-tunnel/blob/51413dcf0534252b5049ec213105c7063ccc6367/index.js#L302-L338).
|
||||
|
||||
In contrast, `global-agent` supports Node.js v10 and above, and does not implements workarounds for the older Node.js versions.
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
export type LogMethod = (context: object | string, message?: string) => void;
|
||||
export type Logger = {
|
||||
child: (context: object) => Logger;
|
||||
debug: LogMethod;
|
||||
error: LogMethod;
|
||||
info: LogMethod;
|
||||
trace: LogMethod;
|
||||
warn: LogMethod;
|
||||
};
|
||||
export declare const setLogger: (newLogger: Logger) => void;
|
||||
export declare const logger: Logger;
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.logger = exports.setLogger = void 0;
|
||||
// oxlint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const noop = () => { };
|
||||
const createNoopLogger = () => {
|
||||
return {
|
||||
child: () => {
|
||||
return createNoopLogger();
|
||||
},
|
||||
debug: noop,
|
||||
error: noop,
|
||||
info: noop,
|
||||
trace: noop,
|
||||
warn: noop,
|
||||
};
|
||||
};
|
||||
let currentLogger = createNoopLogger();
|
||||
const setLogger = (newLogger) => {
|
||||
currentLogger = newLogger;
|
||||
};
|
||||
exports.setLogger = setLogger;
|
||||
const createDelegatingLogger = (getContext) => {
|
||||
const getLogger = () => {
|
||||
let targetLogger = currentLogger;
|
||||
for (const [key, value] of Object.entries(getContext())) {
|
||||
targetLogger = targetLogger.child({ [key]: value });
|
||||
}
|
||||
return targetLogger;
|
||||
};
|
||||
return {
|
||||
child: (context) => {
|
||||
return createDelegatingLogger(() => {
|
||||
return { ...getContext(), ...context };
|
||||
});
|
||||
},
|
||||
debug: (context, message) => {
|
||||
getLogger().debug(context, message);
|
||||
},
|
||||
error: (context, message) => {
|
||||
getLogger().error(context, message);
|
||||
},
|
||||
info: (context, message) => {
|
||||
getLogger().info(context, message);
|
||||
},
|
||||
trace: (context, message) => {
|
||||
getLogger().trace(context, message);
|
||||
},
|
||||
warn: (context, message) => {
|
||||
getLogger().warn(context, message);
|
||||
},
|
||||
};
|
||||
};
|
||||
exports.logger = createDelegatingLogger(() => {
|
||||
return { package: 'global-agent' };
|
||||
});
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/// <reference types="node" />
|
||||
/// <reference types="node" />
|
||||
import type * as http from 'http';
|
||||
import type * as https from 'https';
|
||||
import type { AgentType, ConnectionCallbackType, ConnectionConfigurationType, GetUrlProxyMethodType, IsProxyConfiguredMethodType, MustUrlUseProxyMethodType, ProtocolType } from '../types';
|
||||
type AgentRequestOptions = {
|
||||
host?: string;
|
||||
path?: string;
|
||||
port: number;
|
||||
};
|
||||
type HttpRequestOptions = AgentRequestOptions & Omit<http.RequestOptions, keyof AgentRequestOptions> & {
|
||||
secureEndpoint: false;
|
||||
};
|
||||
type HttpsRequestOptions = AgentRequestOptions & Omit<https.RequestOptions, keyof AgentRequestOptions> & {
|
||||
secureEndpoint: true;
|
||||
};
|
||||
type RequestOptions = HttpRequestOptions | HttpsRequestOptions;
|
||||
declare abstract class Agent {
|
||||
defaultPort: number;
|
||||
protocol: ProtocolType;
|
||||
fallbackAgent: AgentType;
|
||||
isProxyConfigured: IsProxyConfiguredMethodType;
|
||||
mustUrlUseProxy: MustUrlUseProxyMethodType;
|
||||
getUrlProxy: GetUrlProxyMethodType;
|
||||
socketConnectionTimeout: number;
|
||||
ca: string[] | string | undefined;
|
||||
constructor(isProxyConfigured: IsProxyConfiguredMethodType, mustUrlUseProxy: MustUrlUseProxyMethodType, getUrlProxy: GetUrlProxyMethodType, fallbackAgent: AgentType, socketConnectionTimeout: number, ca: string[] | string | undefined);
|
||||
/**
|
||||
* This method can be used to append new ca certificates to existing ca certificates
|
||||
*
|
||||
* @param {string[] | string} ca a ca certificate or an array of ca certificates
|
||||
*/
|
||||
addCACertificates(ca: string[] | string): void;
|
||||
/**
|
||||
* This method clears existing CA Certificates.
|
||||
* It sets ca to undefined
|
||||
*/
|
||||
clearCACertificates(): void;
|
||||
/**
|
||||
* Evaluate value for tls reject unauthorized variable
|
||||
*/
|
||||
getRejectUnauthorized(): boolean;
|
||||
abstract createConnection(configuration: ConnectionConfigurationType, callback: ConnectionCallbackType): void;
|
||||
addRequest(request: http.ClientRequest, configuration: RequestOptions): void;
|
||||
}
|
||||
export default Agent;
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const net_1 = __importDefault(require("net"));
|
||||
const serialize_error_1 = require("serialize-error");
|
||||
const Logger_1 = require("../Logger");
|
||||
const log = Logger_1.logger.child({
|
||||
namespace: 'Agent',
|
||||
});
|
||||
let requestId = 0;
|
||||
class Agent {
|
||||
constructor(isProxyConfigured, mustUrlUseProxy, getUrlProxy, fallbackAgent, socketConnectionTimeout, ca) {
|
||||
this.fallbackAgent = fallbackAgent;
|
||||
this.isProxyConfigured = isProxyConfigured;
|
||||
this.mustUrlUseProxy = mustUrlUseProxy;
|
||||
this.getUrlProxy = getUrlProxy;
|
||||
this.socketConnectionTimeout = socketConnectionTimeout;
|
||||
this.ca = ca;
|
||||
}
|
||||
/**
|
||||
* This method can be used to append new ca certificates to existing ca certificates
|
||||
*
|
||||
* @param {string[] | string} ca a ca certificate or an array of ca certificates
|
||||
*/
|
||||
addCACertificates(ca) {
|
||||
if (!ca) {
|
||||
log.error('Invalid input ca certificate');
|
||||
}
|
||||
else if (this.ca) {
|
||||
if (typeof ca === typeof this.ca) {
|
||||
// concat valid ca certificates with the existing certificates,
|
||||
if (typeof this.ca === 'string') {
|
||||
this.ca = this.ca.concat(ca);
|
||||
}
|
||||
else {
|
||||
this.ca = this.ca.concat(ca);
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.error('Input ca certificate type mismatched with existing ca certificate type');
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.ca = ca;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This method clears existing CA Certificates.
|
||||
* It sets ca to undefined
|
||||
*/
|
||||
clearCACertificates() {
|
||||
this.ca = undefined;
|
||||
}
|
||||
/**
|
||||
* Evaluate value for tls reject unauthorized variable
|
||||
*/
|
||||
getRejectUnauthorized() {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
const rejectUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
|
||||
let returnValue = true;
|
||||
if (typeof rejectUnauthorized === 'boolean') {
|
||||
returnValue = rejectUnauthorized;
|
||||
}
|
||||
else if (typeof rejectUnauthorized === 'number') {
|
||||
returnValue = rejectUnauthorized === 1;
|
||||
}
|
||||
else if (typeof rejectUnauthorized === 'string') {
|
||||
returnValue = ['true', 't', 'yes', 'y', 'on', '1'].includes(rejectUnauthorized.trim().toLowerCase());
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
addRequest(request, configuration) {
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h;
|
||||
let requestUrl;
|
||||
// It is possible that addRequest was constructed for a proxied request already, e.g.
|
||||
// "request" package does this when it detects that a proxy should be used
|
||||
// https://github.com/request/request/blob/212570b6971a732b8dd9f3c73354bcdda158a737/request.js#L402
|
||||
// https://gist.github.com/gajus/e2074cd3b747864ffeaabbd530d30218
|
||||
if ((_a = request.path.startsWith('http://')) !== null && _a !== void 0 ? _a : request.path.startsWith('https://')) {
|
||||
requestUrl = request.path;
|
||||
}
|
||||
else if (request.method === 'CONNECT') {
|
||||
requestUrl = 'https://' + request.path;
|
||||
}
|
||||
else {
|
||||
requestUrl = this.protocol + '//' + ((_b = configuration.hostname) !== null && _b !== void 0 ? _b : configuration.host) + (configuration.port === 80 || configuration.port === 443 ? '' : ':' + configuration.port) + request.path;
|
||||
}
|
||||
// If a request should go to a local socket, proxying it through an HTTP
|
||||
// server does not make sense as the information about the target socket
|
||||
// will be lost and the proxy won't be able to correctly handle the request.
|
||||
if (configuration.socketPath) {
|
||||
log.trace({
|
||||
destination: configuration.socketPath,
|
||||
}, 'not proxying request; destination is a socket');
|
||||
// @ts-expect-error seems like we are using wrong type for fallbackAgent.
|
||||
this.fallbackAgent.addRequest(request, configuration);
|
||||
return;
|
||||
}
|
||||
if (!this.isProxyConfigured()) {
|
||||
log.trace({
|
||||
destination: requestUrl,
|
||||
}, 'not proxying request; GLOBAL_AGENT.HTTP_PROXY is not configured');
|
||||
// @ts-expect-error seems like we are using wrong type for fallbackAgent.
|
||||
this.fallbackAgent.addRequest(request, configuration);
|
||||
return;
|
||||
}
|
||||
if (!this.mustUrlUseProxy(requestUrl)) {
|
||||
log.trace({
|
||||
destination: requestUrl,
|
||||
}, 'not proxying request; url matches GLOBAL_AGENT.NO_PROXY');
|
||||
// @ts-expect-error seems like we are using wrong type for fallbackAgent.
|
||||
this.fallbackAgent.addRequest(request, configuration);
|
||||
return;
|
||||
}
|
||||
const currentRequestId = requestId++;
|
||||
const proxy = this.getUrlProxy(requestUrl);
|
||||
if (this.protocol === 'http:') {
|
||||
request.path = requestUrl;
|
||||
if (proxy.authorization) {
|
||||
request.setHeader('proxy-authorization', 'Basic ' + Buffer.from(proxy.authorization).toString('base64'));
|
||||
}
|
||||
}
|
||||
log.trace({
|
||||
destination: requestUrl,
|
||||
proxy: 'http://' + proxy.hostname + ':' + proxy.port,
|
||||
requestId: currentRequestId,
|
||||
}, 'proxying request');
|
||||
request.on('error', (error) => {
|
||||
log.error({
|
||||
error: (0, serialize_error_1.serializeError)(error),
|
||||
}, 'request error');
|
||||
});
|
||||
request.once('response', (response) => {
|
||||
log.trace({
|
||||
headers: response.headers,
|
||||
requestId: currentRequestId,
|
||||
statusCode: response.statusCode,
|
||||
}, 'proxying response');
|
||||
});
|
||||
request.shouldKeepAlive = false;
|
||||
const connectionConfiguration = {
|
||||
host: (_d = (_c = configuration.hostname) !== null && _c !== void 0 ? _c : configuration.host) !== null && _d !== void 0 ? _d : '',
|
||||
port: (_e = configuration.port) !== null && _e !== void 0 ? _e : 80,
|
||||
proxy,
|
||||
tls: {},
|
||||
};
|
||||
// add optional tls options for https requests.
|
||||
// @see https://nodejs.org/docs/latest-v12.x/api/https.html#https_https_request_url_options_callback :
|
||||
// > The following additional options from tls.connect()
|
||||
// > - https://nodejs.org/docs/latest-v12.x/api/tls.html#tls_tls_connect_options_callback -
|
||||
// > are also accepted:
|
||||
// > ca, cert, ciphers, clientCertEngine, crl, dhparam, ecdhCurve, honorCipherOrder,
|
||||
// > key, passphrase, pfx, rejectUnauthorized, secureOptions, secureProtocol, servername, sessionIdContext.
|
||||
if (configuration.secureEndpoint) {
|
||||
// Determine servername - Node.js doesn't allow IP addresses as servername
|
||||
const host = (_f = configuration.servername) !== null && _f !== void 0 ? _f : connectionConfiguration.host;
|
||||
const servername = net_1.default.isIP(host) ? undefined : host;
|
||||
connectionConfiguration.tls = {
|
||||
ca: (_g = configuration.ca) !== null && _g !== void 0 ? _g : this.ca,
|
||||
cert: configuration.cert,
|
||||
ciphers: configuration.ciphers,
|
||||
clientCertEngine: configuration.clientCertEngine,
|
||||
crl: configuration.crl,
|
||||
dhparam: configuration.dhparam,
|
||||
ecdhCurve: configuration.ecdhCurve,
|
||||
honorCipherOrder: configuration.honorCipherOrder,
|
||||
key: configuration.key,
|
||||
passphrase: configuration.passphrase,
|
||||
pfx: configuration.pfx,
|
||||
rejectUnauthorized: (_h = configuration.rejectUnauthorized) !== null && _h !== void 0 ? _h : this.getRejectUnauthorized(),
|
||||
secureOptions: configuration.secureOptions,
|
||||
secureProtocol: configuration.secureProtocol,
|
||||
servername,
|
||||
sessionIdContext: configuration.sessionIdContext,
|
||||
};
|
||||
}
|
||||
this.createConnection(connectionConfiguration, (error, socket) => {
|
||||
log.trace({
|
||||
target: connectionConfiguration,
|
||||
}, 'connecting');
|
||||
// @see https://github.com/nodejs/node/issues/5757#issuecomment-305969057
|
||||
if (socket) {
|
||||
socket.setTimeout(this.socketConnectionTimeout, () => {
|
||||
socket.destroy();
|
||||
});
|
||||
socket.once('connect', () => {
|
||||
log.trace({
|
||||
target: connectionConfiguration,
|
||||
}, 'connected');
|
||||
socket.setTimeout(0);
|
||||
});
|
||||
socket.once('secureConnect', () => {
|
||||
log.trace({
|
||||
target: connectionConfiguration,
|
||||
}, 'connected (secure)');
|
||||
socket.setTimeout(0);
|
||||
});
|
||||
}
|
||||
if (error) {
|
||||
request.emit('error', error);
|
||||
}
|
||||
else if (socket) {
|
||||
log.debug('created socket');
|
||||
socket.on('error', (socketError) => {
|
||||
log.error({
|
||||
error: (0, serialize_error_1.serializeError)(socketError),
|
||||
}, 'socket error');
|
||||
});
|
||||
request.onSocket(socket);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.default = Agent;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import type { AgentType, ConnectionCallbackType, ConnectionConfigurationType, GetUrlProxyMethodType, IsProxyConfiguredMethodType, MustUrlUseProxyMethodType } from '../types';
|
||||
import Agent from './Agent';
|
||||
declare class HttpProxyAgent extends Agent {
|
||||
constructor(isProxyConfigured: IsProxyConfiguredMethodType, mustUrlUseProxy: MustUrlUseProxyMethodType, getUrlProxy: GetUrlProxyMethodType, fallbackAgent: AgentType, socketConnectionTimeout: number, ca: string[] | string | undefined);
|
||||
createConnection(configuration: ConnectionConfigurationType, callback: ConnectionCallbackType): void;
|
||||
}
|
||||
export default HttpProxyAgent;
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const net_1 = __importDefault(require("net"));
|
||||
const Agent_1 = __importDefault(require("./Agent"));
|
||||
class HttpProxyAgent extends Agent_1.default {
|
||||
// @see https://github.com/sindresorhus/eslint-plugin-unicorn/issues/169#issuecomment-486980290
|
||||
constructor(isProxyConfigured, mustUrlUseProxy, getUrlProxy, fallbackAgent, socketConnectionTimeout, ca) {
|
||||
super(isProxyConfigured, mustUrlUseProxy, getUrlProxy, fallbackAgent, socketConnectionTimeout, ca);
|
||||
this.protocol = 'http:';
|
||||
this.defaultPort = 80;
|
||||
}
|
||||
createConnection(configuration, callback) {
|
||||
const socket = net_1.default.connect(configuration.proxy.port, configuration.proxy.hostname);
|
||||
callback(null, socket);
|
||||
}
|
||||
}
|
||||
exports.default = HttpProxyAgent;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import type { AgentType, ConnectionCallbackType, ConnectionConfigurationType, GetUrlProxyMethodType, IsProxyConfiguredMethodType, MustUrlUseProxyMethodType } from '../types';
|
||||
import Agent from './Agent';
|
||||
declare class HttpsProxyAgent extends Agent {
|
||||
constructor(isProxyConfigured: IsProxyConfiguredMethodType, mustUrlUseProxy: MustUrlUseProxyMethodType, getUrlProxy: GetUrlProxyMethodType, fallbackAgent: AgentType, socketConnectionTimeout: number, ca: string[] | string | undefined);
|
||||
createConnection(configuration: ConnectionConfigurationType, callback: ConnectionCallbackType): void;
|
||||
}
|
||||
export default HttpsProxyAgent;
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const net_1 = __importDefault(require("net"));
|
||||
const tls_1 = __importDefault(require("tls"));
|
||||
const Agent_1 = __importDefault(require("./Agent"));
|
||||
class HttpsProxyAgent extends Agent_1.default {
|
||||
constructor(isProxyConfigured, mustUrlUseProxy, getUrlProxy, fallbackAgent, socketConnectionTimeout, ca) {
|
||||
super(isProxyConfigured, mustUrlUseProxy, getUrlProxy, fallbackAgent, socketConnectionTimeout, ca);
|
||||
this.protocol = 'https:';
|
||||
this.defaultPort = 443;
|
||||
}
|
||||
createConnection(configuration, callback) {
|
||||
const socket = net_1.default.connect(configuration.proxy.port, configuration.proxy.hostname);
|
||||
socket.on('error', (error) => {
|
||||
callback(error);
|
||||
});
|
||||
socket.once('data', (data) => {
|
||||
var _a;
|
||||
// Proxies with HTTPS as protocal are not allowed by parseProxyUrl(), so it should be safe to assume that the response is plain text
|
||||
const statusLine = data.toString().split('\r\n')[0];
|
||||
const statusLineExp = /^HTTP\/(\d)\.(\d) (\d{3}) ?(.*)$/;
|
||||
const statusCode = (_a = statusLineExp.exec(statusLine)) === null || _a === void 0 ? void 0 : _a[3];
|
||||
if (typeof statusCode === 'string' && Number(statusCode) >= 400) {
|
||||
const error = new Error(`Proxy server refused connecting to '${configuration.host}:${configuration.port}' (${statusLine})`);
|
||||
socket.destroy();
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
const secureSocket = tls_1.default.connect({
|
||||
...configuration.tls,
|
||||
socket,
|
||||
});
|
||||
callback(null, secureSocket);
|
||||
});
|
||||
let connectMessage = '';
|
||||
connectMessage += 'CONNECT ' + configuration.host + ':' + configuration.port + ' HTTP/1.1\r\n';
|
||||
connectMessage += 'Host: ' + configuration.host + ':' + configuration.port + '\r\n';
|
||||
if (configuration.proxy.authorization) {
|
||||
connectMessage += 'Proxy-Authorization: Basic ' + Buffer.from(configuration.proxy.authorization).toString('base64') + '\r\n';
|
||||
}
|
||||
connectMessage += '\r\n';
|
||||
socket.write(connectMessage);
|
||||
}
|
||||
}
|
||||
exports.default = HttpsProxyAgent;
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export { default as Agent, } from './Agent';
|
||||
export { default as HttpProxyAgent, } from './HttpProxyAgent';
|
||||
export { default as HttpsProxyAgent, } from './HttpsProxyAgent';
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.HttpsProxyAgent = exports.HttpProxyAgent = exports.Agent = void 0;
|
||||
var Agent_1 = require("./Agent");
|
||||
Object.defineProperty(exports, "Agent", { enumerable: true, get: function () { return __importDefault(Agent_1).default; } });
|
||||
var HttpProxyAgent_1 = require("./HttpProxyAgent");
|
||||
Object.defineProperty(exports, "HttpProxyAgent", { enumerable: true, get: function () { return __importDefault(HttpProxyAgent_1).default; } });
|
||||
var HttpsProxyAgent_1 = require("./HttpsProxyAgent");
|
||||
Object.defineProperty(exports, "HttpsProxyAgent", { enumerable: true, get: function () { return __importDefault(HttpsProxyAgent_1).default; } });
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export declare class UnexpectedStateError extends Error {
|
||||
code: string;
|
||||
constructor(message: string, code?: string);
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.UnexpectedStateError = void 0;
|
||||
class UnexpectedStateError extends Error {
|
||||
constructor(message, code = 'UNEXPECTED_STATE_ERROR') {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
exports.UnexpectedStateError = UnexpectedStateError;
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
import type { ProxyAgentConfigurationInputType } from '../types';
|
||||
declare const _default: (configurationInput?: ProxyAgentConfigurationInputType) => {
|
||||
HTTP_PROXY: string | null;
|
||||
HTTPS_PROXY: string | null;
|
||||
NO_PROXY: string | null;
|
||||
};
|
||||
export default _default;
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const http_1 = __importDefault(require("http"));
|
||||
const https_1 = __importDefault(require("https"));
|
||||
const gte_1 = __importDefault(require("semver/functions/gte"));
|
||||
const Logger_1 = require("../Logger");
|
||||
const classes_1 = require("../classes");
|
||||
const errors_1 = require("../errors");
|
||||
const utilities_1 = require("../utilities");
|
||||
const parseBoolean_1 = require("../utilities/parseBoolean");
|
||||
const createProxyController_1 = __importDefault(require("./createProxyController"));
|
||||
const httpGet = http_1.default.get;
|
||||
const httpRequest = http_1.default.request;
|
||||
const httpsGet = https_1.default.get;
|
||||
const httpsRequest = https_1.default.request;
|
||||
const log = Logger_1.logger.child({
|
||||
namespace: 'createGlobalProxyAgent',
|
||||
});
|
||||
const defaultConfigurationInput = {
|
||||
environmentVariableNamespace: undefined,
|
||||
forceGlobalAgent: undefined,
|
||||
socketConnectionTimeout: 60000,
|
||||
};
|
||||
const createConfiguration = (configurationInput) => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
const environment = process.env;
|
||||
const defaultConfiguration = {
|
||||
environmentVariableNamespace: typeof environment.GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE === 'string' ? environment.GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE : 'GLOBAL_AGENT_',
|
||||
forceGlobalAgent: typeof environment.GLOBAL_AGENT_FORCE_GLOBAL_AGENT === 'string' ? (0, parseBoolean_1.parseBoolean)(environment.GLOBAL_AGENT_FORCE_GLOBAL_AGENT) : true,
|
||||
socketConnectionTimeout: typeof environment.GLOBAL_AGENT_SOCKET_CONNECTION_TIMEOUT === 'string' ? Number.parseInt(environment.GLOBAL_AGENT_SOCKET_CONNECTION_TIMEOUT, 10) : defaultConfigurationInput.socketConnectionTimeout,
|
||||
};
|
||||
return {
|
||||
...defaultConfiguration,
|
||||
...Object.fromEntries(Object.entries(configurationInput).filter(([, v]) => v !== undefined)),
|
||||
};
|
||||
};
|
||||
exports.default = (configurationInput = defaultConfigurationInput) => {
|
||||
var _a, _b, _c;
|
||||
const configuration = createConfiguration(configurationInput);
|
||||
if (configurationInput.logger) {
|
||||
(0, Logger_1.setLogger)(configurationInput.logger);
|
||||
}
|
||||
const proxyController = (0, createProxyController_1.default)();
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
proxyController.HTTP_PROXY = (_a = process.env[configuration.environmentVariableNamespace + 'HTTP_PROXY']) !== null && _a !== void 0 ? _a : null;
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
proxyController.HTTPS_PROXY = (_b = process.env[configuration.environmentVariableNamespace + 'HTTPS_PROXY']) !== null && _b !== void 0 ? _b : null;
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
proxyController.NO_PROXY = (_c = process.env[configuration.environmentVariableNamespace + 'NO_PROXY']) !== null && _c !== void 0 ? _c : null;
|
||||
log.info({
|
||||
configuration,
|
||||
state: proxyController,
|
||||
}, 'global agent has been initialized');
|
||||
const mustUrlUseProxy = (getProxy) => {
|
||||
return (url) => {
|
||||
if (!getProxy()) {
|
||||
return false;
|
||||
}
|
||||
if (!proxyController.NO_PROXY) {
|
||||
return true;
|
||||
}
|
||||
return !(0, utilities_1.isUrlMatchingNoProxy)(url, proxyController.NO_PROXY);
|
||||
};
|
||||
};
|
||||
const getUrlProxy = (getProxy) => {
|
||||
return () => {
|
||||
const proxy = getProxy();
|
||||
if (!proxy) {
|
||||
throw new errors_1.UnexpectedStateError('HTTP(S) proxy must be configured.');
|
||||
}
|
||||
return (0, utilities_1.parseProxyUrl)(proxy);
|
||||
};
|
||||
};
|
||||
const getHttpProxy = () => {
|
||||
return proxyController.HTTP_PROXY;
|
||||
};
|
||||
const BoundHttpProxyAgent = class extends classes_1.HttpProxyAgent {
|
||||
constructor() {
|
||||
super(() => {
|
||||
return Boolean(getHttpProxy());
|
||||
}, mustUrlUseProxy(getHttpProxy), getUrlProxy(getHttpProxy), http_1.default.globalAgent, configuration.socketConnectionTimeout, configuration.ca);
|
||||
}
|
||||
};
|
||||
const httpAgent = new BoundHttpProxyAgent();
|
||||
const getHttpsProxy = () => {
|
||||
var _a;
|
||||
return (_a = proxyController.HTTPS_PROXY) !== null && _a !== void 0 ? _a : proxyController.HTTP_PROXY;
|
||||
};
|
||||
const BoundHttpsProxyAgent = class extends classes_1.HttpsProxyAgent {
|
||||
constructor() {
|
||||
super(() => {
|
||||
return Boolean(getHttpsProxy());
|
||||
}, mustUrlUseProxy(getHttpsProxy), getUrlProxy(getHttpsProxy), https_1.default.globalAgent, configuration.socketConnectionTimeout, configuration.ca);
|
||||
}
|
||||
};
|
||||
const httpsAgent = new BoundHttpsProxyAgent();
|
||||
// Overriding globalAgent was added in v11.7.
|
||||
// @see https://nodejs.org/uk/blog/release/v11.7.0/
|
||||
if ((0, gte_1.default)(process.version, 'v11.7.0')) {
|
||||
// @see https://github.com/facebook/flow/issues/7670
|
||||
// @ts-expect-error Node.js version compatibility
|
||||
http_1.default.globalAgent = httpAgent;
|
||||
// @ts-expect-error Node.js version compatibility
|
||||
https_1.default.globalAgent = httpsAgent;
|
||||
}
|
||||
// The reason this logic is used in addition to overriding http(s).globalAgent
|
||||
// is because there is no guarantee that we set http(s).globalAgent variable
|
||||
// before an instance of http(s).Agent has been already constructed by someone,
|
||||
// e.g. Stripe SDK creates instances of http(s).Agent at the top-level.
|
||||
// @see https://github.com/gajus/global-agent/pull/13
|
||||
//
|
||||
// We still want to override http(s).globalAgent when possible to enable logic
|
||||
// in `bindHttpMethod`.
|
||||
if ((0, gte_1.default)(process.version, 'v10.0.0')) {
|
||||
// @ts-expect-error seems like we are using wrong type for httpAgent
|
||||
http_1.default.get = (0, utilities_1.bindHttpMethod)(httpGet, httpAgent, configuration.forceGlobalAgent);
|
||||
// @ts-expect-error seems like we are using wrong type for httpAgent
|
||||
http_1.default.request = (0, utilities_1.bindHttpMethod)(httpRequest, httpAgent, configuration.forceGlobalAgent);
|
||||
// @ts-expect-error seems like we are using wrong type for httpAgent
|
||||
https_1.default.get = (0, utilities_1.bindHttpMethod)(httpsGet, httpsAgent, configuration.forceGlobalAgent);
|
||||
// @ts-expect-error seems like we are using wrong type for httpAgent
|
||||
https_1.default.request = (0, utilities_1.bindHttpMethod)(httpsRequest, httpsAgent, configuration.forceGlobalAgent);
|
||||
}
|
||||
else {
|
||||
log.warn('attempt to initialize global-agent in unsupported Node.js version was ignored');
|
||||
}
|
||||
return proxyController;
|
||||
};
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Generated
Vendored
+539
@@ -0,0 +1,539 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const http_1 = __importDefault(require("http"));
|
||||
const https_1 = __importDefault(require("https"));
|
||||
const net_1 = __importDefault(require("net"));
|
||||
const vitest_1 = require("vitest");
|
||||
const axios_1 = __importDefault(require("axios"));
|
||||
const get_port_1 = __importDefault(require("get-port"));
|
||||
const got_1 = __importDefault(require("got"));
|
||||
const pem_1 = __importDefault(require("pem"));
|
||||
const request_1 = __importDefault(require("request"));
|
||||
const sinon_1 = require("sinon");
|
||||
const createGlobalProxyAgent_1 = __importDefault(require("./createGlobalProxyAgent"));
|
||||
const defaultHttpAgent = http_1.default.globalAgent;
|
||||
const defaultHttpsAgent = https_1.default.globalAgent;
|
||||
// Backup original value of NODE_TLS_REJECT_UNAUTHORIZED
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
const defaultNodeTlsRejectUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
|
||||
let lastPort = 3000;
|
||||
let localProxyServers = [];
|
||||
let localHttpServers = [];
|
||||
let localHttpsServers = [];
|
||||
let generatedCerts = null;
|
||||
const getNextPort = () => {
|
||||
return (0, get_port_1.default)({
|
||||
port: get_port_1.default.makeRange(lastPort++, 3500),
|
||||
});
|
||||
};
|
||||
// Generate self-signed certificates for HTTPS testing
|
||||
const generateCertificates = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (generatedCerts) {
|
||||
resolve(generatedCerts);
|
||||
return;
|
||||
}
|
||||
pem_1.default.createCertificate({ days: 1, selfSigned: true }, (error, keys) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
generatedCerts = { cert: keys.certificate, key: keys.serviceKey };
|
||||
resolve(generatedCerts);
|
||||
});
|
||||
});
|
||||
};
|
||||
(0, vitest_1.beforeAll)(async () => {
|
||||
// Pre-generate certificates
|
||||
await generateCertificates();
|
||||
});
|
||||
(0, vitest_1.beforeEach)(() => {
|
||||
http_1.default.globalAgent = defaultHttpAgent;
|
||||
https_1.default.globalAgent = defaultHttpsAgent;
|
||||
});
|
||||
(0, vitest_1.afterEach)(() => {
|
||||
for (const localProxyServer of localProxyServers) {
|
||||
localProxyServer.stop();
|
||||
}
|
||||
localProxyServers = [];
|
||||
for (const localHttpServer of localHttpServers) {
|
||||
localHttpServer.stop();
|
||||
}
|
||||
localHttpServers = [];
|
||||
for (const localHttpsServer of localHttpsServers) {
|
||||
localHttpsServer.stop();
|
||||
}
|
||||
localHttpsServers = [];
|
||||
// Reset NODE_TLS_REJECT_UNAUTHORIZED to original value
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = defaultNodeTlsRejectUnauthorized;
|
||||
});
|
||||
const createHttpResponseResolver = (resolve) => {
|
||||
return (response) => {
|
||||
let body = '';
|
||||
response.on('data', (data) => {
|
||||
body += data;
|
||||
});
|
||||
response.on('end', () => {
|
||||
if (!response.headers) {
|
||||
throw new Error('response.headers is not defined');
|
||||
}
|
||||
if (!response.statusCode) {
|
||||
throw new Error('response.statusCode is not defined');
|
||||
}
|
||||
resolve({
|
||||
body,
|
||||
headers: response.headers,
|
||||
statusCode: response.statusCode,
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
// Create a local HTTPS server for CONNECT tunnel targets
|
||||
const createHttpsServer = async () => {
|
||||
const port = await getNextPort();
|
||||
const certs = await generateCertificates();
|
||||
const localHttpsServer = await new Promise((resolve) => {
|
||||
const httpsServer = https_1.default.createServer({
|
||||
cert: certs.cert,
|
||||
key: certs.key,
|
||||
}, (request, response) => {
|
||||
response.writeHead(200, { 'content-type': 'text/plain' });
|
||||
response.end('OK');
|
||||
});
|
||||
httpsServer.listen(port, '127.0.0.1', () => {
|
||||
resolve({
|
||||
port,
|
||||
stop: () => {
|
||||
httpsServer.close();
|
||||
},
|
||||
url: 'https://127.0.0.1:' + port,
|
||||
});
|
||||
});
|
||||
});
|
||||
localHttpsServers.push(localHttpsServer);
|
||||
return localHttpsServer;
|
||||
};
|
||||
// Create a simple HTTP proxy server that can handle both HTTP requests and HTTPS CONNECT tunneling
|
||||
const createProxyServer = async (rules) => {
|
||||
const port = await getNextPort();
|
||||
// Create an HTTPS server that the proxy will tunnel to for CONNECT requests
|
||||
const httpsServer = await createHttpsServer();
|
||||
const localProxyServer = await new Promise((resolve) => {
|
||||
const proxyServer = http_1.default.createServer((request, response) => {
|
||||
// Handle regular HTTP proxy requests
|
||||
if (rules === null || rules === void 0 ? void 0 : rules.beforeSendRequest) {
|
||||
const result = rules.beforeSendRequest({
|
||||
requestOptions: {
|
||||
headers: request.headers,
|
||||
},
|
||||
});
|
||||
response.writeHead(result.response.statusCode, result.response.header);
|
||||
response.end(result.response.body);
|
||||
}
|
||||
else {
|
||||
// Default response
|
||||
response.writeHead(200, { 'content-type': 'text/plain' });
|
||||
response.end('OK');
|
||||
}
|
||||
});
|
||||
// Handle CONNECT requests for HTTPS tunneling
|
||||
proxyServer.on('connect', (request, clientSocket, head) => {
|
||||
// Call onConnect hook if provided
|
||||
if (rules === null || rules === void 0 ? void 0 : rules.onConnect) {
|
||||
rules.onConnect(request);
|
||||
}
|
||||
// Connect to the local HTTPS server instead of the requested host
|
||||
const serverSocket = net_1.default.connect(httpsServer.port, '127.0.0.1', () => {
|
||||
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
|
||||
serverSocket.write(head);
|
||||
serverSocket.pipe(clientSocket);
|
||||
clientSocket.pipe(serverSocket);
|
||||
});
|
||||
serverSocket.on('error', () => {
|
||||
clientSocket.end('HTTP/1.1 500 Internal Server Error\r\n\r\n');
|
||||
});
|
||||
clientSocket.on('error', () => {
|
||||
serverSocket.end();
|
||||
});
|
||||
});
|
||||
proxyServer.listen(port, () => {
|
||||
resolve({
|
||||
httpsServer,
|
||||
port,
|
||||
stop: () => {
|
||||
proxyServer.close();
|
||||
},
|
||||
url: 'http://127.0.0.1:' + port,
|
||||
});
|
||||
});
|
||||
});
|
||||
localProxyServers.push(localProxyServer);
|
||||
return localProxyServer;
|
||||
};
|
||||
const createHttpServer = async () => {
|
||||
const port = await getNextPort();
|
||||
const localHttpServer = await new Promise((resolve) => {
|
||||
const httpServer = http_1.default.createServer((request, response) => {
|
||||
response.end('DIRECT');
|
||||
});
|
||||
httpServer.listen(port, () => {
|
||||
resolve({
|
||||
stop: () => {
|
||||
httpServer.close();
|
||||
},
|
||||
url: 'http://127.0.0.1:' + port,
|
||||
});
|
||||
});
|
||||
});
|
||||
localHttpServers.push(localHttpServer);
|
||||
return localHttpServer;
|
||||
};
|
||||
(0, vitest_1.test)('proxies HTTP request', async () => {
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const response = await new Promise((resolve) => {
|
||||
http_1.default.get('http://127.0.0.1', createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('proxies HTTP request with proxy-authorization header', async () => {
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const beforeSendRequest = (0, sinon_1.stub)().callsFake(() => {
|
||||
return {
|
||||
response: {
|
||||
body: 'OK',
|
||||
header: { 'content-type': 'text/plain' },
|
||||
statusCode: 200,
|
||||
},
|
||||
};
|
||||
});
|
||||
const proxyServer = await createProxyServer({
|
||||
beforeSendRequest,
|
||||
});
|
||||
globalProxyAgent.HTTP_PROXY = 'http://foo@127.0.0.1:' + proxyServer.port;
|
||||
const response = await new Promise((resolve) => {
|
||||
http_1.default.get('http://127.0.0.1', createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
(0, vitest_1.expect)(beforeSendRequest.firstCall.args[0].requestOptions.headers['proxy-authorization']).toBe('Basic Zm9v');
|
||||
});
|
||||
(0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = undefined', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
const { NODE_TLS_REJECT_UNAUTHORIZED, ...restEnvironments } = process.env; // oxlint-disable-line @typescript-eslint/no-unused-vars
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env = restEnvironments;
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.GLOBAL_AGENT_FORCE_GLOBAL_AGENT = 'true';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(true);
|
||||
const response = await new Promise((resolve) => {
|
||||
http_1.default.get('http://127.0.0.1', createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = null', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 'null';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(false);
|
||||
});
|
||||
(0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = 1', async () => {
|
||||
// @ts-expect-error it is expected as we wanted to set process variable with int
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = 0', async () => {
|
||||
// @ts-expect-error it is expected as we wanted to set process variable with int
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(false);
|
||||
});
|
||||
(0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = true', async () => {
|
||||
// @ts-expect-error it is expected as we wanted to set process variable with boolean
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = true;
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = false', async () => {
|
||||
// @ts-expect-error it is expected as we wanted to set process variable with boolean
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = false;
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(false);
|
||||
});
|
||||
(0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = yes', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 'yes';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('Test reject unauthorized variable when NODE_TLS_REJECT_UNAUTHORIZED = no', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 'no';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.getRejectUnauthorized()).toBe(false);
|
||||
});
|
||||
(0, vitest_1.test)('Test addCACertificates and clearCACertificates methods', async () => {
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.ca).toBe(undefined);
|
||||
globalAgent.addCACertificates(['test-ca-certficate1', 'test-ca-certficate2']);
|
||||
globalAgent.addCACertificates(['test-ca-certficate3']);
|
||||
const result = ['test-ca-certficate1', 'test-ca-certficate2', 'test-ca-certficate3'];
|
||||
(0, vitest_1.expect)(globalAgent.ca.length).toBe(result.length);
|
||||
(0, vitest_1.expect)(JSON.stringify(globalAgent.ca)).toBe(JSON.stringify(result));
|
||||
globalAgent.clearCACertificates();
|
||||
(0, vitest_1.expect)(globalAgent.ca).toBe(undefined);
|
||||
});
|
||||
(0, vitest_1.test)('Test addCACertificates when passed ca is a string', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.ca).toBe(undefined);
|
||||
globalAgent.addCACertificates('test-ca-certficate1');
|
||||
globalAgent.addCACertificates('test-ca-certficate2');
|
||||
(0, vitest_1.expect)(globalAgent.ca).toBe('test-ca-certficate1test-ca-certficate2');
|
||||
const response = await new Promise((resolve) => {
|
||||
https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('Test addCACertificates when input ca is a string and existing ca is array', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)({ ca: ['test-ca'] });
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.ca.length).toBe(1);
|
||||
globalAgent.addCACertificates('test-ca-certficate1');
|
||||
(0, vitest_1.expect)(globalAgent.ca.length).toBe(1);
|
||||
(0, vitest_1.expect)(JSON.stringify(globalAgent.ca)).toBe(JSON.stringify(['test-ca']));
|
||||
const response = await new Promise((resolve) => {
|
||||
https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('Test addCACertificates when input ca array is null or undefined', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.ca).toBe(undefined);
|
||||
globalAgent.addCACertificates(undefined);
|
||||
globalAgent.addCACertificates(null);
|
||||
(0, vitest_1.expect)(globalAgent.ca).toBe(undefined);
|
||||
const response = await new Promise((resolve) => {
|
||||
https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('Test initializing ca certificate property while creating global proxy agent', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)({ ca: ['test-ca'] });
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const globalAgent = https_1.default.globalAgent;
|
||||
(0, vitest_1.expect)(globalAgent.ca.length).toBe(1);
|
||||
globalAgent.addCACertificates(['test-ca1']);
|
||||
(0, vitest_1.expect)(globalAgent.ca.length).toBe(2);
|
||||
(0, vitest_1.expect)(globalAgent.ca[0]).toBe('test-ca');
|
||||
(0, vitest_1.expect)(globalAgent.ca[1]).toBe('test-ca1');
|
||||
const response = await new Promise((resolve) => {
|
||||
https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('proxies HTTPS request', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const response = await new Promise((resolve) => {
|
||||
https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('proxies HTTPS request with proxy-authorization header', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const onConnect = (0, sinon_1.stub)();
|
||||
const proxyServer = await createProxyServer({
|
||||
onConnect,
|
||||
});
|
||||
globalProxyAgent.HTTP_PROXY = 'http://foo@127.0.0.1:' + proxyServer.port;
|
||||
const response = await new Promise((resolve) => {
|
||||
https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
(0, vitest_1.expect)(onConnect.firstCall.args[0].headers['proxy-authorization']).toBe('Basic Zm9v');
|
||||
});
|
||||
(0, vitest_1.test)('does not produce unhandled rejection when cannot connect to proxy', async () => {
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const port = await getNextPort();
|
||||
globalProxyAgent.HTTP_PROXY = 'http://127.0.0.1:' + port;
|
||||
await (0, vitest_1.expect)((0, got_1.default)('http://127.0.0.1')).rejects.toThrow();
|
||||
});
|
||||
(0, vitest_1.test)('proxies HTTPS request with dedicated proxy', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTPS_PROXY = proxyServer.url;
|
||||
const response = await new Promise((resolve) => {
|
||||
https_1.default.get('https://127.0.0.1', createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('ignores dedicated HTTPS proxy for HTTP urls', async () => {
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
globalProxyAgent.HTTPS_PROXY = 'http://example.org';
|
||||
const response = await new Promise((resolve) => {
|
||||
http_1.default.get('http://127.0.0.1', {}, createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('forwards requests matching NO_PROXY', async () => {
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
const httpServer = await createHttpServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
globalProxyAgent.NO_PROXY = '127.0.0.1';
|
||||
const response = await new Promise((resolve) => {
|
||||
http_1.default.get(httpServer.url, createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('DIRECT');
|
||||
});
|
||||
(0, vitest_1.test)('forwards requests that go to a socket', async () => {
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
// not relevant as traffic shouldn't go through proxy
|
||||
globalProxyAgent.HTTP_PROXY = 'localhost:10324';
|
||||
const server = http_1.default.createServer((request, serverResponse) => {
|
||||
serverResponse.writeHead(200);
|
||||
serverResponse.write('OK');
|
||||
serverResponse.end();
|
||||
});
|
||||
server.listen('/tmp/test.sock');
|
||||
const response = await new Promise((resolve) => {
|
||||
http_1.default.get({
|
||||
path: '/endpoint',
|
||||
socketPath: '/tmp/test.sock',
|
||||
}, createHttpResponseResolver(resolve));
|
||||
});
|
||||
server.close();
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('proxies HTTP request (using http.get(host))', async () => {
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const response = await new Promise((resolve) => {
|
||||
http_1.default.get({
|
||||
host: '127.0.0.1',
|
||||
}, createHttpResponseResolver(resolve));
|
||||
});
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('proxies HTTP request (using got)', async () => {
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const response = await (0, got_1.default)('http://127.0.0.1');
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('proxies HTTPS request (using got)', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const response = await (0, got_1.default)('https://127.0.0.1');
|
||||
(0, vitest_1.expect)(response.body).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('proxies HTTP request (using axios)', async () => {
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const response = await axios_1.default.get('http://127.0.0.1');
|
||||
(0, vitest_1.expect)(response.data).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('proxies HTTPS request (using axios)', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const response = await axios_1.default.get('https://127.0.0.1');
|
||||
(0, vitest_1.expect)(response.data).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('proxies HTTP request (using request)', async () => {
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const response = await new Promise((resolve) => {
|
||||
(0, request_1.default)('http://127.0.0.1', (error, requestResponse, body) => {
|
||||
(0, vitest_1.expect)(error).toBe(null);
|
||||
resolve(body);
|
||||
});
|
||||
});
|
||||
(0, vitest_1.expect)(response).toBe('OK');
|
||||
});
|
||||
(0, vitest_1.test)('proxies HTTPS request (using request)', async () => {
|
||||
// oxlint-disable-next-line node/no-process-env
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
const globalProxyAgent = (0, createGlobalProxyAgent_1.default)();
|
||||
const proxyServer = await createProxyServer();
|
||||
globalProxyAgent.HTTP_PROXY = proxyServer.url;
|
||||
const response = await new Promise((resolve) => {
|
||||
(0, request_1.default)('https://127.0.0.1', (error, requestResponse, body) => {
|
||||
(0, vitest_1.expect)(error).toBe(null);
|
||||
resolve(body);
|
||||
});
|
||||
});
|
||||
(0, vitest_1.expect)(response).toBe('OK');
|
||||
});
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
type ProxyController = {
|
||||
HTTP_PROXY: string | null;
|
||||
HTTPS_PROXY: string | null;
|
||||
NO_PROXY: string | null;
|
||||
};
|
||||
declare const _default: () => ProxyController;
|
||||
export default _default;
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const Logger_1 = require("../Logger");
|
||||
const log = Logger_1.logger.child({
|
||||
namespace: 'createProxyController',
|
||||
});
|
||||
const KNOWN_PROPERTY_NAMES = [
|
||||
'HTTP_PROXY',
|
||||
'HTTPS_PROXY',
|
||||
'NO_PROXY',
|
||||
];
|
||||
exports.default = () => {
|
||||
// oxlint-disable-next-line fp/no-proxy
|
||||
return new Proxy({
|
||||
HTTP_PROXY: null,
|
||||
HTTPS_PROXY: null,
|
||||
NO_PROXY: null,
|
||||
}, {
|
||||
set: (subject, name, value) => {
|
||||
if (typeof name !== 'string') {
|
||||
throw new TypeError('Unexpected object member.');
|
||||
}
|
||||
if (!KNOWN_PROPERTY_NAMES.includes(name)) {
|
||||
throw new Error('Cannot set an unmapped property "' + name + '".');
|
||||
}
|
||||
// @ts-expect-error string cannot be used to index an object
|
||||
subject[name] = value;
|
||||
log.info({
|
||||
change: {
|
||||
name,
|
||||
value,
|
||||
},
|
||||
newConfiguration: subject,
|
||||
}, 'configuration changed');
|
||||
return true;
|
||||
},
|
||||
});
|
||||
};
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Generated
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const vitest_1 = require("vitest");
|
||||
const createProxyController_1 = __importDefault(require("./createProxyController"));
|
||||
(0, vitest_1.test)('sets HTTP_PROXY', () => {
|
||||
const globalAgentGlobal = (0, createProxyController_1.default)();
|
||||
globalAgentGlobal.HTTP_PROXY = 'http://127.0.0.1';
|
||||
(0, vitest_1.expect)(globalAgentGlobal.HTTP_PROXY).toBe('http://127.0.0.1');
|
||||
});
|
||||
(0, vitest_1.test)('sets HTTPS_PROXY', () => {
|
||||
const globalAgentGlobal = (0, createProxyController_1.default)();
|
||||
globalAgentGlobal.HTTPS_PROXY = 'http://127.0.0.1';
|
||||
(0, vitest_1.expect)(globalAgentGlobal.HTTPS_PROXY).toBe('http://127.0.0.1');
|
||||
});
|
||||
(0, vitest_1.test)('sets NO_PROXY', () => {
|
||||
const globalAgentGlobal = (0, createProxyController_1.default)();
|
||||
globalAgentGlobal.NO_PROXY = '*';
|
||||
(0, vitest_1.expect)(globalAgentGlobal.NO_PROXY).toBe('*');
|
||||
});
|
||||
(0, vitest_1.test)('throws an error if unknown property is set', () => {
|
||||
const globalAgentGlobal = (0, createProxyController_1.default)();
|
||||
(0, vitest_1.expect)(() => {
|
||||
// @ts-expect-error expected unknown property.
|
||||
globalAgentGlobal.FOO = 'BAR';
|
||||
}).toThrow('Cannot set an unmapped property "FOO".');
|
||||
});
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export { default as createGlobalProxyAgent, } from './createGlobalProxyAgent';
|
||||
export { default as createProxyController, } from './createProxyController';
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createProxyController = exports.createGlobalProxyAgent = void 0;
|
||||
var createGlobalProxyAgent_1 = require("./createGlobalProxyAgent");
|
||||
Object.defineProperty(exports, "createGlobalProxyAgent", { enumerable: true, get: function () { return __importDefault(createGlobalProxyAgent_1).default; } });
|
||||
var createProxyController_1 = require("./createProxyController");
|
||||
Object.defineProperty(exports, "createProxyController", { enumerable: true, get: function () { return __importDefault(createProxyController_1).default; } });
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export { bootstrap, } from './routines';
|
||||
export { createGlobalProxyAgent, } from './factories';
|
||||
export type { Logger, } from './Logger';
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createGlobalProxyAgent = exports.bootstrap = void 0;
|
||||
var routines_1 = require("./routines");
|
||||
Object.defineProperty(exports, "bootstrap", { enumerable: true, get: function () { return routines_1.bootstrap; } });
|
||||
var factories_1 = require("./factories");
|
||||
Object.defineProperty(exports, "createGlobalProxyAgent", { enumerable: true, get: function () { return factories_1.createGlobalProxyAgent; } });
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import type { ProxyAgentConfigurationInputType } from '../types';
|
||||
declare const _default: (configurationInput?: ProxyAgentConfigurationInputType) => boolean;
|
||||
export default _default;
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const globalthis_1 = __importDefault(require("globalthis"));
|
||||
const Logger_1 = require("../Logger");
|
||||
const factories_1 = require("../factories");
|
||||
const globalThis = (0, globalthis_1.default)();
|
||||
const log = Logger_1.logger.child({
|
||||
namespace: 'bootstrap',
|
||||
});
|
||||
exports.default = (configurationInput) => {
|
||||
if (globalThis.GLOBAL_AGENT) {
|
||||
log.warn('found globalThis.GLOBAL_AGENT; second attempt to bootstrap global-agent was ignored');
|
||||
return false;
|
||||
}
|
||||
globalThis.GLOBAL_AGENT = (0, factories_1.createGlobalProxyAgent)(configurationInput);
|
||||
return true;
|
||||
};
|
||||
+1
@@ -0,0 +1 @@
|
||||
export { default as bootstrap, } from './bootstrap';
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.bootstrap = void 0;
|
||||
var bootstrap_1 = require("./bootstrap");
|
||||
Object.defineProperty(exports, "bootstrap", { enumerable: true, get: function () { return __importDefault(bootstrap_1).default; } });
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/// <reference types="node" />
|
||||
/// <reference types="node" />
|
||||
/// <reference types="node" />
|
||||
/// <reference types="node" />
|
||||
import type { Agent as HttpAgent } from 'http';
|
||||
import type { Agent as HttpsAgent } from 'https';
|
||||
import type { Socket } from 'net';
|
||||
import type { TLSSocket } from 'tls';
|
||||
import type { Logger } from './Logger';
|
||||
export type ProxyConfigurationType = {
|
||||
authorization: string | null;
|
||||
hostname: string;
|
||||
port: number;
|
||||
};
|
||||
export type TlsConfigurationType = {
|
||||
ca?: string[] | string;
|
||||
cert?: string;
|
||||
ciphers?: string;
|
||||
clientCertEngine?: string;
|
||||
crl?: string;
|
||||
dhparam?: string;
|
||||
ecdhCurve?: string;
|
||||
honorCipherOrder?: boolean;
|
||||
key?: string;
|
||||
passphrase?: string;
|
||||
pfx?: string;
|
||||
rejectUnauthorized?: boolean;
|
||||
secureOptions?: number;
|
||||
secureProtocol?: string;
|
||||
servername?: string;
|
||||
sessionIdContext?: string;
|
||||
};
|
||||
export type ConnectionConfigurationType = {
|
||||
host: string;
|
||||
port: number;
|
||||
tls?: TlsConfigurationType;
|
||||
proxy: ProxyConfigurationType;
|
||||
};
|
||||
export type ConnectionCallbackType = (error: Error | null, socket?: Socket | TLSSocket) => void;
|
||||
export type AgentType = HttpAgent | HttpsAgent;
|
||||
export type IsProxyConfiguredMethodType = () => boolean;
|
||||
export type MustUrlUseProxyMethodType = (url: string) => boolean;
|
||||
export type GetUrlProxyMethodType = (url: string) => ProxyConfigurationType;
|
||||
export type ProtocolType = 'http:' | 'https:';
|
||||
export type ProxyAgentConfigurationInputType = {
|
||||
environmentVariableNamespace?: string;
|
||||
forceGlobalAgent?: boolean;
|
||||
socketConnectionTimeout?: number;
|
||||
ca?: string[] | string;
|
||||
logger?: Logger;
|
||||
};
|
||||
export type ProxyAgentConfigurationType = {
|
||||
environmentVariableNamespace: string;
|
||||
forceGlobalAgent: boolean;
|
||||
socketConnectionTimeout: number;
|
||||
ca?: string[] | string;
|
||||
};
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
/// <reference types="node" />
|
||||
/// <reference types="node" />
|
||||
import http from 'http';
|
||||
import https from 'https';
|
||||
type AgentType = http.Agent | https.Agent;
|
||||
declare const _default: (originalMethod: Function, agent: AgentType, forceGlobalAgent: boolean) => (...args: any[]) => any;
|
||||
export default _default;
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const http_1 = __importDefault(require("http"));
|
||||
const https_1 = __importDefault(require("https"));
|
||||
exports.default = (originalMethod, agent, forceGlobalAgent) => {
|
||||
return (...args) => {
|
||||
let url;
|
||||
let options;
|
||||
let callback;
|
||||
if (typeof args[0] === 'string' || args[0] instanceof URL) {
|
||||
url = args[0];
|
||||
if (typeof args[1] === 'function') {
|
||||
options = {};
|
||||
callback = args[1];
|
||||
}
|
||||
else {
|
||||
options = {
|
||||
...args[1],
|
||||
};
|
||||
callback = args[2];
|
||||
}
|
||||
}
|
||||
else {
|
||||
options = {
|
||||
...args[0],
|
||||
};
|
||||
callback = args[1];
|
||||
}
|
||||
if (forceGlobalAgent) {
|
||||
options.agent = agent;
|
||||
}
|
||||
else {
|
||||
if (!options.agent) {
|
||||
options.agent = agent;
|
||||
}
|
||||
if (options.agent === http_1.default.globalAgent || options.agent === https_1.default.globalAgent) {
|
||||
options.agent = agent;
|
||||
}
|
||||
}
|
||||
if (url) {
|
||||
return originalMethod(url, options, callback);
|
||||
}
|
||||
else {
|
||||
return originalMethod(options, callback);
|
||||
}
|
||||
};
|
||||
};
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export { default as bindHttpMethod, } from './bindHttpMethod';
|
||||
export { default as isUrlMatchingNoProxy, } from './isUrlMatchingNoProxy';
|
||||
export { default as parseProxyUrl, } from './parseProxyUrl';
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.parseProxyUrl = exports.isUrlMatchingNoProxy = exports.bindHttpMethod = void 0;
|
||||
var bindHttpMethod_1 = require("./bindHttpMethod");
|
||||
Object.defineProperty(exports, "bindHttpMethod", { enumerable: true, get: function () { return __importDefault(bindHttpMethod_1).default; } });
|
||||
var isUrlMatchingNoProxy_1 = require("./isUrlMatchingNoProxy");
|
||||
Object.defineProperty(exports, "isUrlMatchingNoProxy", { enumerable: true, get: function () { return __importDefault(isUrlMatchingNoProxy_1).default; } });
|
||||
var parseProxyUrl_1 = require("./parseProxyUrl");
|
||||
Object.defineProperty(exports, "parseProxyUrl", { enumerable: true, get: function () { return __importDefault(parseProxyUrl_1).default; } });
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
declare const _default: (subjectUrl: string, noProxy: string) => boolean;
|
||||
export default _default;
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const matcher_1 = __importDefault(require("matcher"));
|
||||
const errors_1 = require("../errors");
|
||||
exports.default = (subjectUrl, noProxy) => {
|
||||
const subjectUrlTokens = new URL(subjectUrl);
|
||||
const rules = noProxy.split(/[\s,]+/).filter(Boolean);
|
||||
for (const rule of rules) {
|
||||
const ruleMatch = rule
|
||||
.replace(/^(?<leadingDot>\.)/, '*')
|
||||
.match(/^(?<hostname>.+?)(?::(?<port>\d+))?$/);
|
||||
if (!ruleMatch || !ruleMatch.groups) {
|
||||
throw new errors_1.UnexpectedStateError('Invalid NO_PROXY pattern.');
|
||||
}
|
||||
if (!ruleMatch.groups.hostname) {
|
||||
throw new errors_1.UnexpectedStateError('NO_PROXY entry pattern must include hostname. Use * to match any hostname.');
|
||||
}
|
||||
const hostnameIsMatch = matcher_1.default.isMatch(subjectUrlTokens.hostname, ruleMatch.groups.hostname);
|
||||
if (hostnameIsMatch && (!ruleMatch.groups || !ruleMatch.groups.port || subjectUrlTokens.port && subjectUrlTokens.port === ruleMatch.groups.port)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Generated
Vendored
+61
@@ -0,0 +1,61 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const vitest_1 = require("vitest");
|
||||
const isUrlMatchingNoProxy_1 = __importDefault(require("./isUrlMatchingNoProxy"));
|
||||
(0, vitest_1.test)('returns `true` if hosts match', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com/', 'foo.com')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if hosts match (IP)', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://127.0.0.1/', '127.0.0.1')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if hosts match (using asterisk wildcard)', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://bar.foo.com/', '*.foo.com')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if domain matches (using dot wildcard)', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com/', '.foo.com')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if subdomain matches (using dot wildcard)', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://bar.foo.com/', '.foo.com')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if hosts match (*) and ports match', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com:8080/', '*:8080')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if hosts and ports match', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com:8080/', 'foo.com:8080')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if hosts match and NO_PROXY does not define port', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com:8080/', 'foo.com')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if hosts (IP) and ports match', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://127.0.0.1:8080/', '127.0.0.1:8080')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `false` if hosts match and ports do not match (diffferent port)', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com:8080/', 'foo.com:8000')).toBe(false);
|
||||
});
|
||||
(0, vitest_1.test)('returns `false` if hosts match and ports do not match (port not present subject)', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com/', 'foo.com:8000')).toBe(false);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if hosts match and ports do not match (port not present NO_PROXY)', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com:8000/', 'foo.com')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if hosts match in one of multiple rules separated with a comma', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com/', 'bar.org,foo.com,baz.io')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if hosts match in one of multiple rules separated with a comma and a space', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com/', 'bar.org, foo.com, baz.io')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('returns `true` if hosts match in one of multiple rules separated with a space', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com/', 'bar.org foo.com baz.io')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('handles trailing newline in NO_PROXY', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com/', 'foo.com\n')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('handles trailing whitespace in NO_PROXY', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com/', 'foo.com ')).toBe(true);
|
||||
});
|
||||
(0, vitest_1.test)('handles leading whitespace in NO_PROXY', () => {
|
||||
(0, vitest_1.expect)((0, isUrlMatchingNoProxy_1.default)('http://foo.com/', ' foo.com')).toBe(true);
|
||||
});
|
||||
+1
@@ -0,0 +1 @@
|
||||
export declare const parseBoolean: (value: any) => boolean;
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.parseBoolean = void 0;
|
||||
const parseBoolean = function (value) {
|
||||
switch (Object.prototype.toString.call(value)) {
|
||||
case '[object String]':
|
||||
return ['true', 't', 'yes', 'y', 'on', '1'].includes(value.trim().toLowerCase());
|
||||
case '[object Number]':
|
||||
return value.valueOf() === 1;
|
||||
case '[object Boolean]':
|
||||
return value.valueOf();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
exports.parseBoolean = parseBoolean;
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
declare const _default: (url: string) => {
|
||||
authorization: string | null;
|
||||
hostname: string;
|
||||
port: number;
|
||||
};
|
||||
export default _default;
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const errors_1 = require("../errors");
|
||||
exports.default = (url) => {
|
||||
const urlTokens = new URL(url);
|
||||
if (urlTokens.search !== '') {
|
||||
throw new errors_1.UnexpectedStateError('Unsupported `GLOBAL_AGENT.HTTP_PROXY` configuration value: URL must not have query.');
|
||||
}
|
||||
if (urlTokens.hash !== '') {
|
||||
throw new errors_1.UnexpectedStateError('Unsupported `GLOBAL_AGENT.HTTP_PROXY` configuration value: URL must not have hash.');
|
||||
}
|
||||
if (urlTokens.protocol !== 'http:') {
|
||||
throw new errors_1.UnexpectedStateError('Unsupported `GLOBAL_AGENT.HTTP_PROXY` configuration value: URL protocol must be "http:".');
|
||||
}
|
||||
let port = 80;
|
||||
if (urlTokens.port) {
|
||||
port = Number.parseInt(urlTokens.port, 10);
|
||||
}
|
||||
let authorization = null;
|
||||
if (urlTokens.username && urlTokens.password) {
|
||||
authorization = urlTokens.username + ':' + urlTokens.password;
|
||||
}
|
||||
else if (urlTokens.username) {
|
||||
authorization = urlTokens.username;
|
||||
}
|
||||
return {
|
||||
authorization,
|
||||
hostname: urlTokens.hostname,
|
||||
port,
|
||||
};
|
||||
};
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const vitest_1 = require("vitest");
|
||||
const parseProxyUrl_1 = __importDefault(require("./parseProxyUrl"));
|
||||
(0, vitest_1.test)('extracts hostname', () => {
|
||||
(0, vitest_1.expect)((0, parseProxyUrl_1.default)('http://0.0.0.0').hostname).toBe('0.0.0.0');
|
||||
});
|
||||
(0, vitest_1.test)('extracts port', () => {
|
||||
(0, vitest_1.expect)((0, parseProxyUrl_1.default)('http://0.0.0.0:3000').port).toBe(3000);
|
||||
});
|
||||
(0, vitest_1.test)('extracts authorization', () => {
|
||||
(0, vitest_1.expect)((0, parseProxyUrl_1.default)('http://foo:bar@0.0.0.0').authorization).toBe('foo:bar');
|
||||
});
|
||||
(0, vitest_1.test)('throws an error if protocol is not "http:"', () => {
|
||||
(0, vitest_1.expect)(() => {
|
||||
(0, parseProxyUrl_1.default)('https://0.0.0.0:3000');
|
||||
}).toThrow('Unsupported `GLOBAL_AGENT.HTTP_PROXY` configuration value: URL protocol must be "http:".');
|
||||
});
|
||||
(0, vitest_1.test)('throws an error if query is present', () => {
|
||||
(0, vitest_1.expect)(() => {
|
||||
(0, parseProxyUrl_1.default)('http://0.0.0.0:3000/?foo=bar');
|
||||
}).toThrow('Unsupported `GLOBAL_AGENT.HTTP_PROXY` configuration value: URL must not have query.');
|
||||
});
|
||||
(0, vitest_1.test)('throws an error if hash is present', () => {
|
||||
(0, vitest_1.expect)(() => {
|
||||
(0, parseProxyUrl_1.default)('http://0.0.0.0:3000/#foo');
|
||||
}).toThrow('Unsupported `GLOBAL_AGENT.HTTP_PROXY` configuration value: URL must not have hash.');
|
||||
});
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"author": {
|
||||
"email": "gajus@gajus.com",
|
||||
"name": "Gajus Kuizinas",
|
||||
"url": "https://gajus.com"
|
||||
},
|
||||
"dependencies": {
|
||||
"globalthis": "^1.0.2",
|
||||
"matcher": "^4.0.0",
|
||||
"semver": "^7.3.5",
|
||||
"serialize-error": "^8.1.0"
|
||||
},
|
||||
"description": "Global HTTP/HTTPS proxy configurable using environment variables.",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.14.8",
|
||||
"@babel/core": "^7.14.8",
|
||||
"@babel/node": "^7.14.7",
|
||||
"@babel/plugin-transform-flow-strip-types": "^7.14.5",
|
||||
"@babel/preset-env": "^7.14.8",
|
||||
"@babel/register": "^7.14.5",
|
||||
"@semantic-release/commit-analyzer": "^13.0.1",
|
||||
"@semantic-release/github": "^12.0.3",
|
||||
"@semantic-release/npm": "^13.1.3",
|
||||
"@types/globalthis": "^1.0.1",
|
||||
"@types/pem": "^1.14.4",
|
||||
"@types/request": "^2.48.6",
|
||||
"@types/semver": "^7.3.8",
|
||||
"@types/sinon": "^10.0.2",
|
||||
"axios": "^0.21.1",
|
||||
"babel-plugin-transform-export-default-name": "^2.1.0",
|
||||
"del-cli": "^4.0.1",
|
||||
"get-port": "^5.1.1",
|
||||
"got": "^11.8.2",
|
||||
"husky": "^7.0.1",
|
||||
"oxlint": "^1.43.0",
|
||||
"pem": "^1.14.4",
|
||||
"request": "^2.88.2",
|
||||
"semantic-release": "^25.0.3",
|
||||
"sinon": "^11.1.2",
|
||||
"ts-node": "^10.1.0",
|
||||
"typescript": "^4.3.5",
|
||||
"vitest": "^4.0.18"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10.0"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "npm run lint && npm run test && npm run build"
|
||||
}
|
||||
},
|
||||
"keywords": [
|
||||
"http",
|
||||
"global",
|
||||
"proxy",
|
||||
"agent"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"main": "./dist/index.js",
|
||||
"name": "global-agent",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/gajus/global-agent"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "del-cli ./dist && tsc",
|
||||
"lint": "oxlint ./src && tsc",
|
||||
"test": "vitest run",
|
||||
"create-readme": "gitdown ./.README/README.md --output-file ./README.md"
|
||||
},
|
||||
"typings": "./dist/src/index.d.ts",
|
||||
"version": "4.1.3"
|
||||
}
|
||||
Reference in New Issue
Block a user