-
Notifications
You must be signed in to change notification settings - Fork 88
/
Copy pathproxy-config.ts
118 lines (102 loc) · 4.61 KB
/
proxy-config.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import * as _ from 'lodash';
import { MaybePromise } from '../util/type-utils';
import { RuleParameterReference } from './rule-parameters';
/**
* A ProxySetting is a specific proxy setting to use, which is passed to a proxy agent
* who will manage creating a socket for the request (directly, or tunnelled, or whatever).
*/
export interface ProxySetting {
/**
* The URL for the proxy to forward traffic through.
*
* This can be any URL supported by https://www.npmjs.com/package/proxy-agent.
* For example: http://..., socks5://..., pac+http://...
*/
proxyUrl: string;
/**
* A list of no-proxy values, matching hosts' traffic should *not* be proxied.
*
* This is a common proxy feature, but unfortunately isn't standardized. See
* https://about.gitlab.com/blog/2021/01/27/we-need-to-talk-no-proxy/ for some
* background. This implementation is intended to match Curl's behaviour, and
* any differences are a bug.
*
* The currently supported formats are:
* - example.com (matches domain and all subdomains)
* - example.com:443 (matches domain and all subdomains, but only on that port)
* - 10.0.0.1 (matches IP, but only when used directly - does not resolve domains)
*
* Some other formats (e.g. leading dots or *.) will work, but the leading
* characters are ignored. More formats may be added in future, e.g. CIDR ranges.
* To maximize compatibility with values used elsewhere, unrecognized formats
* will generally be ignored, but may match in unexpected ways.
*/
noProxy?: string[];
/**
* CAs to trust for HTTPS connections to the proxy. Ignored if the connection to
* the proxy is not HTTPS. If not specified, this will default to the Node
* defaults, or you can override them here completely.
*
* Note that unlike passthrough rule's `trustAdditionalCAs` option, this sets the
* complete list of trusted CAs - not just additional ones.
*/
trustedCAs?: string[];
}
/**
* A ProxySettingSource is a way to calculate the ProxySetting for a given request. It
* may be a fixed ProxySetting value, or a callback to get ProxySetting values, or an
* array of sources, which should be iterated to get the first usable value
*/
export type ProxySettingSource =
| ProxySetting
| ProxySettingCallback
| Array<ProxySettingSource>
| undefined;
export type ProxySettingCallbackParams = { hostname: string };
export type ProxySettingCallback = (params: ProxySettingCallbackParams) => MaybePromise<ProxySetting | undefined>;
/**
* A ProxyConfig is externally provided config that specifies a ProxySettingSource.
* It might be a ProxySettingSource itself, or it might include references to rule
* parameters, which must be dereferenced to make it usable as a ProxySettingSource.
*/
export type ProxyConfig =
| ProxySettingSource
| RuleParameterReference<ProxySettingSource>
| Array<ProxySettingSource | RuleParameterReference<ProxySettingSource>>;
export async function getProxySetting(
configSource: ProxySettingSource,
params: ProxySettingCallbackParams
) {
if (_.isFunction(configSource)) return configSource(params);
else if (_.isArray(configSource)) {
let result: ProxySetting | undefined;
for (let configArrayOption of configSource) {
result = await getProxySetting(configArrayOption, params);
if (result) break;
}
return result;
}
else return configSource;
}
export const matchesNoProxy = (hostname: string, portNum: number, noProxyValues: string[] | undefined) => {
if (!noProxyValues || noProxyValues.length === 0) return false; // Skip everything in the common case.
const port = portNum.toString();
const hostParts = hostname.split('.').reverse();
return noProxyValues.some((noProxy) => {
const [noProxyHost, noProxyPort] = noProxy.split(':') as [string, string | undefined];
let noProxyParts = noProxyHost.split('.').reverse();
const lastPart = noProxyParts[noProxyParts.length - 1];
if (lastPart === '' || lastPart === '*') {
noProxyParts = noProxyParts.slice(0, -1);
}
if (noProxyPort && port !== noProxyPort) return false;
for (let i = 0; i < noProxyParts.length; i++) {
let noProxyPart = noProxyParts[i];
let hostPart = hostParts[i];
if (hostPart === undefined) return false; // No-proxy is longer than hostname
if (noProxyPart !== hostPart) return false; // Mismatch
}
// If we run out of no-proxy parts with no mismatch then we've matched
return true;
});
}