summaryrefslogtreecommitdiff
path: root/desktop/node_modules/global-agent/src
diff options
context:
space:
mode:
authorRaindropsSys <raindrops@equestria.dev>2023-10-24 17:43:37 +0200
committerRaindropsSys <raindrops@equestria.dev>2023-10-24 17:43:37 +0200
commitae187b6d75c8079da0be1dc288613bad8466fe61 (patch)
tree5ea0d34185a2270f29ffaa65e1f5258028d7d5d0 /desktop/node_modules/global-agent/src
downloadmist-ae187b6d75c8079da0be1dc288613bad8466fe61.tar.gz
mist-ae187b6d75c8079da0be1dc288613bad8466fe61.tar.bz2
mist-ae187b6d75c8079da0be1dc288613bad8466fe61.zip
Initial commit
Diffstat (limited to 'desktop/node_modules/global-agent/src')
-rw-r--r--desktop/node_modules/global-agent/src/Logger.js10
-rw-r--r--desktop/node_modules/global-agent/src/classes/Agent.js212
-rw-r--r--desktop/node_modules/global-agent/src/classes/HttpProxyAgent.js30
-rw-r--r--desktop/node_modules/global-agent/src/classes/HttpsProxyAgent.js54
-rw-r--r--desktop/node_modules/global-agent/src/classes/index.js5
-rw-r--r--desktop/node_modules/global-agent/src/errors.js15
-rw-r--r--desktop/node_modules/global-agent/src/factories/createGlobalProxyAgent.js197
-rw-r--r--desktop/node_modules/global-agent/src/factories/createProxyController.js46
-rw-r--r--desktop/node_modules/global-agent/src/factories/index.js4
-rw-r--r--desktop/node_modules/global-agent/src/index.js4
-rw-r--r--desktop/node_modules/global-agent/src/routines/bootstrap.js25
-rw-r--r--desktop/node_modules/global-agent/src/routines/index.js3
-rw-r--r--desktop/node_modules/global-agent/src/types.js66
-rw-r--r--desktop/node_modules/global-agent/src/utilities/bindHttpMethod.js54
-rw-r--r--desktop/node_modules/global-agent/src/utilities/index.js5
-rw-r--r--desktop/node_modules/global-agent/src/utilities/isUrlMatchingNoProxy.js37
-rw-r--r--desktop/node_modules/global-agent/src/utilities/parseProxyUrl.js36
17 files changed, 803 insertions, 0 deletions
diff --git a/desktop/node_modules/global-agent/src/Logger.js b/desktop/node_modules/global-agent/src/Logger.js
new file mode 100644
index 0000000..166f1e4
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/Logger.js
@@ -0,0 +1,10 @@
+// @flow
+
+import Roarr from 'roarr';
+
+const Logger = Roarr
+ .child({
+ package: 'global-agent',
+ });
+
+export default Logger;
diff --git a/desktop/node_modules/global-agent/src/classes/Agent.js b/desktop/node_modules/global-agent/src/classes/Agent.js
new file mode 100644
index 0000000..801dd1f
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/classes/Agent.js
@@ -0,0 +1,212 @@
+// @flow
+
+import {
+ serializeError,
+} from 'serialize-error';
+import {
+ boolean,
+} from 'boolean';
+import Logger from '../Logger';
+import type {
+ AgentType,
+ GetUrlProxyMethodType,
+ IsProxyConfiguredMethodType,
+ MustUrlUseProxyMethodType,
+ ProtocolType,
+} from '../types';
+
+const log = Logger.child({
+ namespace: 'Agent',
+});
+
+let requestId = 0;
+
+class Agent {
+ defaultPort: number;
+
+ protocol: ProtocolType;
+
+ fallbackAgent: AgentType;
+
+ isProxyConfigured: IsProxyConfiguredMethodType;
+
+ mustUrlUseProxy: MustUrlUseProxyMethodType;
+
+ getUrlProxy: GetUrlProxyMethodType;
+
+ socketConnectionTimeout: number;
+
+ constructor (
+ isProxyConfigured: IsProxyConfiguredMethodType,
+ mustUrlUseProxy: MustUrlUseProxyMethodType,
+ getUrlProxy: GetUrlProxyMethodType,
+ fallbackAgent: AgentType,
+ socketConnectionTimeout: number,
+ ) {
+ this.fallbackAgent = fallbackAgent;
+ this.isProxyConfigured = isProxyConfigured;
+ this.mustUrlUseProxy = mustUrlUseProxy;
+ this.getUrlProxy = getUrlProxy;
+ this.socketConnectionTimeout = socketConnectionTimeout;
+ }
+
+ addRequest (request: *, configuration: *) {
+ 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 (request.path.startsWith('http://') || request.path.startsWith('https://')) {
+ requestUrl = request.path;
+ } else {
+ requestUrl = this.protocol + '//' + (configuration.hostname || configuration.host) + (configuration.port === 80 || configuration.port === 443 ? '' : ':' + configuration.port) + request.path;
+ }
+
+ if (!this.isProxyConfigured()) {
+ log.trace({
+ destination: requestUrl,
+ }, 'not proxying request; GLOBAL_AGENT.HTTP_PROXY is not configured');
+
+ // $FlowFixMe It appears that Flow is missing the method description.
+ this.fallbackAgent.addRequest(request, configuration);
+
+ return;
+ }
+
+ if (!this.mustUrlUseProxy(requestUrl)) {
+ log.trace({
+ destination: requestUrl,
+ }, 'not proxying request; url matches GLOBAL_AGENT.NO_PROXY');
+
+ // $FlowFixMe It appears that Flow is missing the method description.
+ 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: 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: configuration.hostname || configuration.host,
+ port: configuration.port || 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 (this.protocol === 'https:') {
+ connectionConfiguration.tls = {
+ ca: configuration.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: configuration.rejectUnauthorized,
+ 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.
+ //
+ // eslint-disable-next-line no-process-env
+ if (typeof process.env.NODE_TLS_REJECT_UNAUTHORIZED === 'string' && boolean(process.env.NODE_TLS_REJECT_UNAUTHORIZED) === false) {
+ connectionConfiguration.tls.rejectUnauthorized = false;
+ }
+ }
+
+ // $FlowFixMe It appears that Flow is missing the method description.
+ 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 {
+ log.debug('created socket');
+
+ socket.on('error', (socketError) => {
+ log.error({
+ error: serializeError(socketError),
+ }, 'socket error');
+ });
+
+ request.onSocket(socket);
+ }
+ });
+ }
+}
+
+export default Agent;
diff --git a/desktop/node_modules/global-agent/src/classes/HttpProxyAgent.js b/desktop/node_modules/global-agent/src/classes/HttpProxyAgent.js
new file mode 100644
index 0000000..8b9b471
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/classes/HttpProxyAgent.js
@@ -0,0 +1,30 @@
+// @flow
+
+import net from 'net';
+import type {
+ ConnectionCallbackType,
+ ConnectionConfigurationType,
+} from '../types';
+import Agent from './Agent';
+
+class HttpProxyAgent extends Agent {
+ // @see https://github.com/sindresorhus/eslint-plugin-unicorn/issues/169#issuecomment-486980290
+ // eslint-disable-next-line unicorn/prevent-abbreviations
+ constructor (...args: *) {
+ super(...args);
+
+ this.protocol = 'http:';
+ this.defaultPort = 80;
+ }
+
+ createConnection (configuration: ConnectionConfigurationType, callback: ConnectionCallbackType) {
+ const socket = net.connect(
+ configuration.proxy.port,
+ configuration.proxy.hostname,
+ );
+
+ callback(null, socket);
+ }
+}
+
+export default HttpProxyAgent;
diff --git a/desktop/node_modules/global-agent/src/classes/HttpsProxyAgent.js b/desktop/node_modules/global-agent/src/classes/HttpsProxyAgent.js
new file mode 100644
index 0000000..24d724f
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/classes/HttpsProxyAgent.js
@@ -0,0 +1,54 @@
+// @flow
+
+import net from 'net';
+import tls from 'tls';
+import type {
+ ConnectionCallbackType,
+ ConnectionConfigurationType,
+} from '../types';
+import Agent from './Agent';
+
+class HttpsProxyAgent extends Agent {
+ // eslint-disable-next-line unicorn/prevent-abbreviations
+ constructor (...args: *) {
+ super(...args);
+
+ this.protocol = 'https:';
+ this.defaultPort = 443;
+ }
+
+ createConnection (configuration: ConnectionConfigurationType, callback: ConnectionCallbackType) {
+ const socket = net.connect(
+ configuration.proxy.port,
+ configuration.proxy.hostname,
+ );
+
+ socket.on('error', (error) => {
+ callback(error);
+ });
+
+ socket.once('data', () => {
+ const secureSocket = tls.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);
+ }
+}
+
+export default HttpsProxyAgent;
diff --git a/desktop/node_modules/global-agent/src/classes/index.js b/desktop/node_modules/global-agent/src/classes/index.js
new file mode 100644
index 0000000..9e8418a
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/classes/index.js
@@ -0,0 +1,5 @@
+// @flow
+
+export {default as Agent} from './Agent';
+export {default as HttpProxyAgent} from './HttpProxyAgent';
+export {default as HttpsProxyAgent} from './HttpsProxyAgent';
diff --git a/desktop/node_modules/global-agent/src/errors.js b/desktop/node_modules/global-agent/src/errors.js
new file mode 100644
index 0000000..d93ba6f
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/errors.js
@@ -0,0 +1,15 @@
+// @flow
+
+/* eslint-disable fp/no-class, fp/no-this */
+
+import ExtendableError from 'es6-error';
+
+export class UnexpectedStateError extends ExtendableError {
+ code: string;
+
+ constructor (message: string, code: string = 'UNEXPECTED_STATE_ERROR') {
+ super(message);
+
+ this.code = code;
+ }
+}
diff --git a/desktop/node_modules/global-agent/src/factories/createGlobalProxyAgent.js b/desktop/node_modules/global-agent/src/factories/createGlobalProxyAgent.js
new file mode 100644
index 0000000..d515a9d
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/factories/createGlobalProxyAgent.js
@@ -0,0 +1,197 @@
+// @flow
+
+import http from 'http';
+import https from 'https';
+import {
+ boolean as parseBoolean,
+} from 'boolean';
+import semver from 'semver';
+import Logger from '../Logger';
+import {
+ HttpProxyAgent,
+ HttpsProxyAgent,
+} from '../classes';
+import {
+ UnexpectedStateError,
+} from '../errors';
+import {
+ bindHttpMethod,
+ isUrlMatchingNoProxy,
+ parseProxyUrl,
+} from '../utilities';
+import type {
+ ProxyAgentConfigurationInputType,
+ ProxyAgentConfigurationType,
+} from '../types';
+import createProxyController from './createProxyController';
+
+const httpGet = http.get;
+const httpRequest = http.request;
+const httpsGet = https.get;
+const httpsRequest = https.request;
+
+const log = Logger.child({
+ namespace: 'createGlobalProxyAgent',
+});
+
+const defaultConfigurationInput = {
+ environmentVariableNamespace: undefined,
+ forceGlobalAgent: undefined,
+ socketConnectionTimeout: 60000,
+};
+
+const omitUndefined = (subject) => {
+ const keys = Object.keys(subject);
+
+ const result = {};
+
+ for (const key of keys) {
+ const value = subject[key];
+
+ if (value !== undefined) {
+ result[key] = value;
+ }
+ }
+
+ return result;
+};
+
+const createConfiguration = (configurationInput: ProxyAgentConfigurationInputType): ProxyAgentConfigurationType => {
+ // eslint-disable-next-line 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' ? 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,
+ };
+
+ // $FlowFixMe
+ return {
+ ...defaultConfiguration,
+ ...omitUndefined(configurationInput),
+ };
+};
+
+export default (configurationInput: ProxyAgentConfigurationInputType = defaultConfigurationInput) => {
+ const configuration = createConfiguration(configurationInput);
+
+ const proxyController = createProxyController();
+
+ // eslint-disable-next-line no-process-env
+ proxyController.HTTP_PROXY = process.env[configuration.environmentVariableNamespace + 'HTTP_PROXY'] || null;
+
+ // eslint-disable-next-line no-process-env
+ proxyController.HTTPS_PROXY = process.env[configuration.environmentVariableNamespace + 'HTTPS_PROXY'] || null;
+
+ // eslint-disable-next-line no-process-env
+ proxyController.NO_PROXY = process.env[configuration.environmentVariableNamespace + 'NO_PROXY'] || 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 !isUrlMatchingNoProxy(url, proxyController.NO_PROXY);
+ };
+ };
+
+ const getUrlProxy = (getProxy) => {
+ return () => {
+ const proxy = getProxy();
+
+ if (!proxy) {
+ throw new UnexpectedStateError('HTTP(S) proxy must be configured.');
+ }
+
+ return parseProxyUrl(proxy);
+ };
+ };
+
+ const getHttpProxy = () => {
+ return proxyController.HTTP_PROXY;
+ };
+
+ const BoundHttpProxyAgent = class extends HttpProxyAgent {
+ constructor () {
+ super(
+ () => {
+ return getHttpProxy();
+ },
+ mustUrlUseProxy(getHttpProxy),
+ getUrlProxy(getHttpProxy),
+ http.globalAgent,
+ configuration.socketConnectionTimeout,
+ );
+ }
+ };
+
+ const httpAgent = new BoundHttpProxyAgent();
+
+ const getHttpsProxy = () => {
+ return proxyController.HTTPS_PROXY || proxyController.HTTP_PROXY;
+ };
+
+ const BoundHttpsProxyAgent = class extends HttpsProxyAgent {
+ constructor () {
+ super(
+ () => {
+ return getHttpsProxy();
+ },
+ mustUrlUseProxy(getHttpsProxy),
+ getUrlProxy(getHttpsProxy),
+ https.globalAgent,
+ configuration.socketConnectionTimeout,
+ );
+ }
+ };
+
+ const httpsAgent = new BoundHttpsProxyAgent();
+
+ // Overriding globalAgent was added in v11.7.
+ // @see https://nodejs.org/uk/blog/release/v11.7.0/
+ if (semver.gte(process.version, 'v11.7.0')) {
+ // @see https://github.com/facebook/flow/issues/7670
+ // $FlowFixMe
+ http.globalAgent = httpAgent;
+
+ // $FlowFixMe
+ https.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 (semver.gte(process.version, 'v10.0.0')) {
+ // $FlowFixMe
+ http.get = bindHttpMethod(httpGet, httpAgent, configuration.forceGlobalAgent);
+
+ // $FlowFixMe
+ http.request = bindHttpMethod(httpRequest, httpAgent, configuration.forceGlobalAgent);
+
+ // $FlowFixMe
+ https.get = bindHttpMethod(httpsGet, httpsAgent, configuration.forceGlobalAgent);
+
+ // $FlowFixMe
+ https.request = bindHttpMethod(httpsRequest, httpsAgent, configuration.forceGlobalAgent);
+ } else {
+ log.warn('attempt to initialize global-agent in unsupported Node.js version was ignored');
+ }
+
+ return proxyController;
+};
diff --git a/desktop/node_modules/global-agent/src/factories/createProxyController.js b/desktop/node_modules/global-agent/src/factories/createProxyController.js
new file mode 100644
index 0000000..5805ec8
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/factories/createProxyController.js
@@ -0,0 +1,46 @@
+// @flow
+
+import Logger from '../Logger';
+
+type ProxyControllerType = {|
+ HTTP_PROXY: string | null,
+ HTTPS_PROXY: string | null,
+ NO_PROXY: string | null,
+|};
+
+const log = Logger.child({
+ namespace: 'createProxyController',
+});
+
+const KNOWN_PROPERTY_NAMES = [
+ 'HTTP_PROXY',
+ 'HTTPS_PROXY',
+ 'NO_PROXY',
+];
+
+export default (): ProxyControllerType => {
+ // eslint-disable-next-line fp/no-proxy
+ return new Proxy({
+ HTTP_PROXY: null,
+ HTTPS_PROXY: null,
+ NO_PROXY: null,
+ }, {
+ set: (subject, name, value) => {
+ if (!KNOWN_PROPERTY_NAMES.includes(name)) {
+ throw new Error('Cannot set an unmapped property "' + name + '".');
+ }
+
+ subject[name] = value;
+
+ log.info({
+ change: {
+ name,
+ value,
+ },
+ newConfiguration: subject,
+ }, 'configuration changed');
+
+ return true;
+ },
+ });
+};
diff --git a/desktop/node_modules/global-agent/src/factories/index.js b/desktop/node_modules/global-agent/src/factories/index.js
new file mode 100644
index 0000000..c16eca6
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/factories/index.js
@@ -0,0 +1,4 @@
+// @flow
+
+export {default as createGlobalProxyAgent} from './createGlobalProxyAgent';
+export {default as createProxyController} from './createProxyController';
diff --git a/desktop/node_modules/global-agent/src/index.js b/desktop/node_modules/global-agent/src/index.js
new file mode 100644
index 0000000..14da1ba
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/index.js
@@ -0,0 +1,4 @@
+// @flow
+
+export {bootstrap} from './routines';
+export {createGlobalProxyAgent} from './factories';
diff --git a/desktop/node_modules/global-agent/src/routines/bootstrap.js b/desktop/node_modules/global-agent/src/routines/bootstrap.js
new file mode 100644
index 0000000..038feb3
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/routines/bootstrap.js
@@ -0,0 +1,25 @@
+// @flow
+
+import Logger from '../Logger';
+import {
+ createGlobalProxyAgent,
+} from '../factories';
+import type {
+ ProxyAgentConfigurationInputType,
+} from '../types';
+
+const log = Logger.child({
+ namespace: 'bootstrap',
+});
+
+export default (configurationInput?: ProxyAgentConfigurationInputType): boolean => {
+ if (global.GLOBAL_AGENT) {
+ log.warn('found global.GLOBAL_AGENT; second attempt to bootstrap global-agent was ignored');
+
+ return false;
+ }
+
+ global.GLOBAL_AGENT = createGlobalProxyAgent(configurationInput);
+
+ return true;
+};
diff --git a/desktop/node_modules/global-agent/src/routines/index.js b/desktop/node_modules/global-agent/src/routines/index.js
new file mode 100644
index 0000000..e47a8a0
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/routines/index.js
@@ -0,0 +1,3 @@
+// @flow
+
+export {default as bootstrap} from './bootstrap';
diff --git a/desktop/node_modules/global-agent/src/types.js b/desktop/node_modules/global-agent/src/types.js
new file mode 100644
index 0000000..e2f1a99
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/types.js
@@ -0,0 +1,66 @@
+// @flow
+
+import {
+ Socket,
+} from 'net';
+import {
+ TLSSocket,
+} from 'tls';
+import {
+ Agent as HttpAgent,
+} from 'http';
+import {
+ Agent as HttpsAgent,
+} from 'https';
+
+export type ProxyConfigurationType = {|
+ +authorization: string,
+ +hostname: string,
+ +port: number,
+|};
+
+export type TlsConfigurationType = {|
+ +ca?: 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,
+|};
+
+export type ProxyAgentConfigurationType = {|
+ +environmentVariableNamespace: string,
+ +forceGlobalAgent: boolean,
+ +socketConnectionTimeout: number,
+|};
diff --git a/desktop/node_modules/global-agent/src/utilities/bindHttpMethod.js b/desktop/node_modules/global-agent/src/utilities/bindHttpMethod.js
new file mode 100644
index 0000000..f8859b5
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/utilities/bindHttpMethod.js
@@ -0,0 +1,54 @@
+// @flow
+
+import http from 'http';
+import https from 'https';
+
+type AgentType = http.Agent | https.Agent;
+
+// eslint-disable-next-line flowtype/no-weak-types
+export default (originalMethod: Function, agent: AgentType, forceGlobalAgent: boolean) => {
+ // eslint-disable-next-line unicorn/prevent-abbreviations
+ 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.globalAgent || options.agent === https.globalAgent) {
+ options.agent = agent;
+ }
+ }
+
+ if (url) {
+ // $FlowFixMe
+ return originalMethod(url, options, callback);
+ } else {
+ return originalMethod(options, callback);
+ }
+ };
+};
diff --git a/desktop/node_modules/global-agent/src/utilities/index.js b/desktop/node_modules/global-agent/src/utilities/index.js
new file mode 100644
index 0000000..3412387
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/utilities/index.js
@@ -0,0 +1,5 @@
+// @flow
+
+export {default as bindHttpMethod} from './bindHttpMethod';
+export {default as isUrlMatchingNoProxy} from './isUrlMatchingNoProxy';
+export {default as parseProxyUrl} from './parseProxyUrl';
diff --git a/desktop/node_modules/global-agent/src/utilities/isUrlMatchingNoProxy.js b/desktop/node_modules/global-agent/src/utilities/isUrlMatchingNoProxy.js
new file mode 100644
index 0000000..f2de584
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/utilities/isUrlMatchingNoProxy.js
@@ -0,0 +1,37 @@
+// @flow
+
+import {
+ parse as parseUrl,
+} from 'url';
+import matcher from 'matcher';
+import {
+ UnexpectedStateError,
+} from '../errors';
+
+export default (subjectUrl: string, noProxy: string) => {
+ const subjectUrlTokens = parseUrl(subjectUrl);
+
+ const rules = noProxy.split(/[\s,]+/);
+
+ for (const rule of rules) {
+ const ruleMatch = rule
+ .replace(/^(?<leadingDot>\.)/, '*')
+ .match(/^(?<hostname>.+?)(?::(?<port>\d+))?$/);
+
+ if (!ruleMatch || !ruleMatch.groups) {
+ throw new UnexpectedStateError('Invalid NO_PROXY pattern.');
+ }
+
+ if (!ruleMatch.groups.hostname) {
+ throw new UnexpectedStateError('NO_PROXY entry pattern must include hostname. Use * to match any hostname.');
+ }
+
+ const hostnameIsMatch = matcher.isMatch(subjectUrlTokens.hostname, ruleMatch.groups.hostname);
+
+ if (hostnameIsMatch && (!ruleMatch.groups || !ruleMatch.groups.port || subjectUrlTokens.port && subjectUrlTokens.port === ruleMatch.groups.port)) {
+ return true;
+ }
+ }
+
+ return false;
+};
diff --git a/desktop/node_modules/global-agent/src/utilities/parseProxyUrl.js b/desktop/node_modules/global-agent/src/utilities/parseProxyUrl.js
new file mode 100644
index 0000000..e2e9a6b
--- /dev/null
+++ b/desktop/node_modules/global-agent/src/utilities/parseProxyUrl.js
@@ -0,0 +1,36 @@
+// @flow
+
+import {
+ parse as parseUrl,
+} from 'url';
+import {
+ UnexpectedStateError,
+} from '../errors';
+
+export default (url: string) => {
+ const urlTokens = parseUrl(url);
+
+ if (urlTokens.query !== null) {
+ throw new UnexpectedStateError('Unsupported `GLOBAL_AGENT.HTTP_PROXY` configuration value: URL must not have query.');
+ }
+
+ if (urlTokens.hash !== null) {
+ throw new UnexpectedStateError('Unsupported `GLOBAL_AGENT.HTTP_PROXY` configuration value: URL must not have hash.');
+ }
+
+ if (urlTokens.protocol !== 'http:') {
+ throw new 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);
+ }
+
+ return {
+ authorization: urlTokens.auth || null,
+ hostname: urlTokens.hostname,
+ port,
+ };
+};