Skip to content

Commit

Permalink
Merge 693210c into a3c390e
Browse files Browse the repository at this point in the history
  • Loading branch information
vipendra-mehra committed Sep 1, 2021
2 parents a3c390e + 693210c commit c9ab8d2
Show file tree
Hide file tree
Showing 7 changed files with 321 additions and 14 deletions.
57 changes: 57 additions & 0 deletions README.md
Expand Up @@ -166,11 +166,13 @@ Use [`roarr-cli`](https://github.com/gajus/roarr-cli) program to pretty-print th
* @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.
*/
type ProxyAgentConfigurationInputType = {|
+environmentVariableNamespace?: string,
+forceGlobalAgent?: boolean,
+socketConnectionTimeout?: number,
+ca?: string[] | string,
|};

(configurationInput: ProxyAgentConfigurationInputType) => ProxyAgentConfigurationType;
Expand Down Expand Up @@ -200,6 +202,61 @@ type ProxyAgentConfigurationInputType = {|
|`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,
this.ca = this.ca.concat(ca);
} 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).
Expand Down
68 changes: 55 additions & 13 deletions src/classes/Agent.ts
Expand Up @@ -51,18 +51,71 @@ abstract class Agent {

public socketConnectionTimeout: number;

public ca: string[] | string | undefined;

public constructor (
isProxyConfigured: IsProxyConfiguredMethodType,
mustUrlUseProxy: MustUrlUseProxyMethodType,
getUrlProxy: GetUrlProxyMethodType,
fallbackAgent: AgentType,
socketConnectionTimeout: number,
ca: string[] | string | undefined,
) {
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
*/
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;
}
}

/**
* This method clears existing CA Certificates.
* It sets ca to undefined
*/
public clearCACertificates () {
this.ca = undefined;
}

/**
* Evaluate value for tls reject unauthorized variable
*/
public getRejectUnauthorized () {
// eslint-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;
}

public abstract createConnection (configuration: ConnectionConfigurationType, callback: ConnectionCallbackType): void;
Expand Down Expand Up @@ -152,7 +205,7 @@ abstract class Agent {
// > key, passphrase, pfx, rejectUnauthorized, secureOptions, secureProtocol, servername, sessionIdContext.
if (configuration.secureEndpoint) {
connectionConfiguration.tls = {
ca: configuration.ca,
ca: configuration.ca ?? this.ca,
cert: configuration.cert,
ciphers: configuration.ciphers,
clientCertEngine: configuration.clientCertEngine,
Expand All @@ -163,23 +216,12 @@ abstract class Agent {
key: configuration.key,
passphrase: configuration.passphrase,
pfx: configuration.pfx,
rejectUnauthorized: configuration.rejectUnauthorized ?? true,
rejectUnauthorized: configuration.rejectUnauthorized ?? this.getRejectUnauthorized(),
secureOptions: configuration.secureOptions,
secureProtocol: configuration.secureProtocol,
servername: configuration.servername ?? connectionConfiguration.host,
sessionIdContext: configuration.sessionIdContext,
};

// This is not ideal because there is no way to override this setting using `tls` configuration if `NODE_TLS_REJECT_UNAUTHORIZED=0`.
// However, popular HTTP clients (such as https://github.com/sindresorhus/got) come with pre-configured value for `rejectUnauthorized`,
// which makes it impossible to override that value globally and respect `rejectUnauthorized` for specific requests only.
if (
// eslint-disable-next-line node/no-process-env
process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0'
) {
// @ts-expect-error seems like we are using wrong guard for this change that does not align with secureEndpoint
connectionConfiguration.tls.rejectUnauthorized = false;
}
}

this.createConnection(connectionConfiguration, (error, socket) => {
Expand Down
2 changes: 2 additions & 0 deletions src/classes/HttpProxyAgent.ts
Expand Up @@ -17,13 +17,15 @@ class HttpProxyAgent extends Agent {
getUrlProxy: GetUrlProxyMethodType,
fallbackAgent: AgentType,
socketConnectionTimeout: number,
ca: string[] | string | undefined,
) {
super(
isProxyConfigured,
mustUrlUseProxy,
getUrlProxy,
fallbackAgent,
socketConnectionTimeout,
ca,
);

this.protocol = 'http:';
Expand Down
2 changes: 2 additions & 0 deletions src/classes/HttpsProxyAgent.ts
Expand Up @@ -17,13 +17,15 @@ class HttpsProxyAgent extends Agent {
getUrlProxy: GetUrlProxyMethodType,
fallbackAgent: AgentType,
socketConnectionTimeout: number,
ca: string[] | string | undefined,
) {
super(
isProxyConfigured,
mustUrlUseProxy,
getUrlProxy,
fallbackAgent,
socketConnectionTimeout,
ca,
);

this.protocol = 'https:';
Expand Down
2 changes: 2 additions & 0 deletions src/factories/createGlobalProxyAgent.ts
Expand Up @@ -116,6 +116,7 @@ export default (configurationInput: ProxyAgentConfigurationInputType = defaultCo
getUrlProxy(getHttpProxy),
http.globalAgent,
configuration.socketConnectionTimeout,
configuration.ca,
);
}
};
Expand All @@ -136,6 +137,7 @@ export default (configurationInput: ProxyAgentConfigurationInputType = defaultCo
getUrlProxy(getHttpsProxy),
https.globalAgent,
configuration.socketConnectionTimeout,
configuration.ca,
);
}
};
Expand Down
4 changes: 3 additions & 1 deletion src/types.ts
Expand Up @@ -18,7 +18,7 @@ export type ProxyConfigurationType = {
};

export type TlsConfigurationType = {
ca?: string,
ca?: string[] | string,
cert?: string,
ciphers?: string,
clientCertEngine?: string,
Expand Down Expand Up @@ -55,10 +55,12 @@ export type ProxyAgentConfigurationInputType = {
environmentVariableNamespace?: string,
forceGlobalAgent?: boolean,
socketConnectionTimeout?: number,
ca?: string[] | string,
};

export type ProxyAgentConfigurationType = {
environmentVariableNamespace: string,
forceGlobalAgent: boolean,
socketConnectionTimeout: number,
ca?: string[] | string,
};

0 comments on commit c9ab8d2

Please sign in to comment.