Skip to content

Commit 790aa6c

Browse files
committed
fix: add check for protocol and hostname and treat unset enabled as 'false'
1 parent b7fa2b3 commit 790aa6c

2 files changed

Lines changed: 53 additions & 4 deletions

File tree

src/proxy/routes/index.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,13 +204,24 @@ let _cachedProxyAgent: { proxyUrl: string; agent: HttpsProxyAgent<string> } | nu
204204

205205
const getOrCreateProxyAgent = (proxyUrl: string): HttpsProxyAgent<string> => {
206206
if (!_cachedProxyAgent || _cachedProxyAgent.proxyUrl !== proxyUrl) {
207+
let parsed: URL;
207208
try {
208-
new URL(proxyUrl);
209+
parsed = new URL(proxyUrl);
209210
} catch {
210211
throw new Error(
211212
`Invalid upstream proxy URL: check your upstreamProxy.url config or HTTPS_PROXY env var`,
212213
);
213214
}
215+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
216+
throw new Error(
217+
`Unsupported upstream proxy URL scheme "${parsed.protocol.replace(/:$/, '')}": only http and https are supported`,
218+
);
219+
}
220+
if (!parsed.hostname) {
221+
throw new Error(
222+
`Invalid upstream proxy URL: hostname is missing — check your upstreamProxy.url config or HTTPS_PROXY env var`,
223+
);
224+
}
214225
_cachedProxyAgent = { proxyUrl, agent: new HttpsProxyAgent(proxyUrl) };
215226
}
216227
return _cachedProxyAgent.agent;
@@ -225,7 +236,8 @@ const buildUpstreamProxyAgent = (
225236

226237
const proxyUrl = url || getEnvProxyUrl();
227238

228-
if (enabled === false || !proxyUrl) {
239+
// If enabled is not existant or false
240+
if (enabled === undefined || enabled === false || !proxyUrl) {
229241
return undefined;
230242
}
231243

@@ -382,4 +394,5 @@ export {
382394
validGitRequest,
383395
buildUpstreamProxyAgent,
384396
hostMatchesNoProxy,
397+
getOrCreateProxyAgent,
385398
};

test/upstreamProxy.test.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
1818

19-
import { buildUpstreamProxyAgent } from '../src/proxy/routes';
19+
import { buildUpstreamProxyAgent, getOrCreateProxyAgent } from '../src/proxy/routes';
2020
import * as config from '../src/config';
2121

2222
vi.mock('../src/config', async (importOriginal) => {
@@ -27,6 +27,42 @@ vi.mock('../src/config', async (importOriginal) => {
2727
};
2828
});
2929

30+
describe('getOrCreateProxyAgent', () => {
31+
it('accepts http:// URLs', () => {
32+
expect(() => getOrCreateProxyAgent('http://proxy.example.com:8080')).not.toThrow();
33+
});
34+
35+
it('accepts https:// URLs', () => {
36+
expect(() => getOrCreateProxyAgent('https://proxy.example.com:8080')).not.toThrow();
37+
});
38+
39+
it('rejects socks5:// URLs with a descriptive error', () => {
40+
expect(() => getOrCreateProxyAgent('socks5://proxy.example.com:1080')).toThrow(
41+
/unsupported.*scheme.*socks5/i,
42+
);
43+
});
44+
45+
it('rejects ftp:// URLs with a descriptive error', () => {
46+
expect(() => getOrCreateProxyAgent('ftp://proxy.example.com:21')).toThrow(
47+
/unsupported.*scheme.*ftp/i,
48+
);
49+
});
50+
51+
it('rejects URLs without a protocol (no scheme)', () => {
52+
expect(() => getOrCreateProxyAgent('localhost:8081')).toThrow(
53+
/Unsupported upstream proxy URL scheme/i,
54+
);
55+
});
56+
57+
it('rejects URLs with an empty hostname', () => {
58+
expect(() => getOrCreateProxyAgent('http://:8080')).toThrow(/invalid upstream proxy url/i);
59+
});
60+
61+
it('rejects completely invalid URL strings', () => {
62+
expect(() => getOrCreateProxyAgent('not a url at all')).toThrow(/invalid upstream proxy url/i);
63+
});
64+
});
65+
3066
describe('buildUpstreamProxyAgent', () => {
3167
const originalEnv = process.env;
3268

@@ -69,7 +105,7 @@ describe('buildUpstreamProxyAgent', () => {
69105

70106
it('creates an agent when only HTTPS_PROXY is set and config is empty', () => {
71107
process.env.HTTPS_PROXY = 'http://env-proxy.example.com:8080';
72-
vi.mocked(config.getUpstreamProxyConfig).mockReturnValue({});
108+
vi.mocked(config.getUpstreamProxyConfig).mockReturnValue({ enabled: true });
73109

74110
const agent = buildUpstreamProxyAgent({ host: 'github.com', headers: {} });
75111
expect(agent).toBeDefined();

0 commit comments

Comments
 (0)