Skip to content

Commit b8273a9

Browse files
committed
Support additional upstream proxy connection formats
1 parent 1f831b2 commit b8273a9

File tree

1 file changed

+40
-3
lines changed

1 file changed

+40
-3
lines changed

src/components/settings/connection-settings-card.tsx

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,24 @@ const UpstreamProxyDropdown = styled(Select)`
7070
margin-right: 10px;
7171
`;
7272

73+
const HOST_PATTERN = '[A-Za-z0-9\\-.]+';
74+
const PORT_PATTERN = '\\d+';
75+
// Disallow "@", "/" and ":" in username/password
76+
const CRED_PATTERN = '[^@/:]+';
77+
78+
const PROXY_HOST_REGEXES = [
79+
// 0) host or host:port
80+
new RegExp(`^(${HOST_PATTERN})(:${PORT_PATTERN})?$`),
81+
// 1) user:pass@host:port
82+
new RegExp(`^(${CRED_PATTERN}):(${CRED_PATTERN})@(${HOST_PATTERN}):(${PORT_PATTERN})$`),
83+
// 2) host:port@user:pass
84+
new RegExp(`^(${HOST_PATTERN}):(${PORT_PATTERN})@(${CRED_PATTERN}):(${CRED_PATTERN})$`),
85+
// 3) host:port:user:pass
86+
new RegExp(`^(${HOST_PATTERN}):(${PORT_PATTERN}):(${CRED_PATTERN}):(${CRED_PATTERN})$`),
87+
// 4) user:pass:host:port
88+
new RegExp(`^(${CRED_PATTERN}):(${CRED_PATTERN}):(${HOST_PATTERN}):(${PORT_PATTERN})$`),
89+
];
90+
7391
const isValidClientCertHost = (input: string): boolean =>
7492
isValidHost(input) || input === '*';
7593

@@ -82,11 +100,30 @@ const validateClientCertHost = inputValidation(isValidClientCertHost,
82100
);
83101

84102
const isValidProxyHost = (host: string | undefined): boolean =>
85-
!!host?.match(/^([^/@]*@)?[A-Za-z0-9\-.]+(:\d+)?$/);
103+
!!host && PROXY_HOST_REGEXES.some(regex => regex.test(host));
86104
const validateProxyHost = inputValidation(isValidProxyHost,
87105
"Should be a plain hostname, optionally with a specific port and/or username:password"
88106
);
89107

108+
// Translates the proxy host input into standard form if needed
109+
const normalizeProxyHost = (host: string): string => {
110+
const idx = PROXY_HOST_REGEXES.findIndex(regex => regex.test(host));
111+
if (idx === -1) return host; // Should not occur
112+
113+
const groups = host.match(PROXY_HOST_REGEXES[idx])!;
114+
115+
switch (idx) {
116+
case 2: // host:port@user:pass
117+
return `${groups[3]}:${groups[4]}@${groups[1]}:${groups[2]}`;
118+
case 3: // host:port:user:pass
119+
return `${groups[3]}:${groups[4]}@${groups[1]}:${groups[2]}`;
120+
case 4: // user:pass:host:port
121+
return `${groups[1]}:${groups[2]}@${groups[3]}:${groups[4]}`;
122+
default: // Does not include auth or already in standard format
123+
return host;
124+
}
125+
};
126+
90127
@observer
91128
class UpstreamProxyConfig extends React.Component<{ rulesStore: RulesStore }> {
92129

@@ -126,7 +163,7 @@ class UpstreamProxyConfig extends React.Component<{ rulesStore: RulesStore }> {
126163
// We update the rules store proxy type only at the point where we save the host:
127164
const rulesStore = this.props.rulesStore;
128165
rulesStore.upstreamProxyType = this.proxyType;
129-
rulesStore.upstreamProxyHost = this.proxyHostInput;
166+
rulesStore.upstreamProxyHost = normalizeProxyHost(this.proxyHostInput);
130167
}
131168

132169
@action.bound
@@ -216,7 +253,7 @@ class UpstreamProxyConfig extends React.Component<{ rulesStore: RulesStore }> {
216253
<SettingsButton
217254
disabled={
218255
!isValidProxyHost(proxyHostInput) ||
219-
(proxyHostInput === savedProxyHost && proxyType === savedProxyType)
256+
(normalizeProxyHost(proxyHostInput) === savedProxyHost && proxyType === savedProxyType)
220257
}
221258
onClick={saveProxyHost}
222259
>

0 commit comments

Comments
 (0)