Skip to content

Commit b448744

Browse files
SUNx2YCHdrazisil-codecov
authored andcommitted
fix: use token param for upstream proxy auth
1 parent acf4d83 commit b448744

File tree

4 files changed

+97
-81
lines changed

4 files changed

+97
-81
lines changed

src/helpers/proxy.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,37 @@
11
import { ProxyAgent } from 'undici';
22
import { UploaderArgs, UploaderEnvs } from '../types.js';
3-
import { IncomingHttpHeaders } from 'undici/types/header.js';
3+
import { logError } from './logger'
44

5-
export function addProxyIfNeeded(envs: UploaderEnvs, args: UploaderArgs): ProxyAgent | undefined {
6-
return args.upstream ? new ProxyAgent({ uri: args.upstream }) : undefined;
5+
export function getBasicAuthToken(username: string, password: string): string {
6+
const authString = Buffer.from(`${username}:${password}`).toString('base64')
7+
return `Basic ${authString}`
8+
}
9+
10+
export function removeUrlAuth(url: string | URL): string {
11+
const noAuthUrl = new URL(url)
12+
noAuthUrl.username = ''
13+
noAuthUrl.password = ''
14+
return noAuthUrl.href
715
}
816

9-
export function addProxyHeaders(envs: UploaderEnvs, initialHeaders: IncomingHttpHeaders): IncomingHttpHeaders {
10-
let headers: IncomingHttpHeaders
11-
if (envs['PROXY_BASIC_USER'] && envs['PROXY_BASIC_PASS']) {
12-
const authString = Buffer.from(`${envs['PROXY_BASIC_USER']}:${envs['PROXY_BASIC_PASS']}`).toString("base64")
13-
headers = { ...initialHeaders, Authorization: `Basic ${authString}` }
14-
} else {
15-
headers = initialHeaders
17+
export function addProxyIfNeeded(envs: UploaderEnvs, args: UploaderArgs): ProxyAgent | undefined {
18+
if (!args.upstream) {
19+
return undefined
1620
}
17-
return headers
21+
22+
// https://github.com/nodejs/undici/blob/main/docs/api/ProxyAgent.md#example---basic-proxy-request-with-authentication
23+
try {
24+
const proxyUrl = new URL(args.upstream)
25+
if (proxyUrl.username && proxyUrl.password) {
26+
return new ProxyAgent({
27+
uri: removeUrlAuth(proxyUrl),
28+
token: getBasicAuthToken(proxyUrl.username, proxyUrl.password),
29+
})
30+
}
31+
return new ProxyAgent({ uri: args.upstream })
32+
} catch (err) {
33+
logError(`Couldn't set upstream proxy: ${err}`)
34+
}
35+
36+
return undefined
1837
}

src/helpers/web.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ import {
1616
UploaderInputs,
1717
} from '../types'
1818
import { info } from './logger'
19-
import { addProxyHeaders, addProxyIfNeeded } from './proxy'
20-
import { IncomingHttpHeaders } from 'undici/types/header.js'
19+
import { addProxyIfNeeded } from './proxy'
2120

2221
/**
2322
*
@@ -175,13 +174,11 @@ export function generateRequestHeadersPOST(
175174
source,
176175
)}&token=${token}&${query}`, postURL)
177176

178-
const initialHeaders = {
177+
const headers = {
179178
'X-Upload-Token': token,
180179
'X-Reduced-Redundancy': 'false',
181180
}
182181

183-
const headers: IncomingHttpHeaders = addProxyHeaders(envs, initialHeaders)
184-
185182
return {
186183
agent: addProxyIfNeeded(envs, args),
187184
url: url,
@@ -202,12 +199,10 @@ export function generateRequestHeadersPUT(
202199
envs: UploaderEnvs,
203200
args: UploaderArgs,
204201
): IRequestHeaders {
205-
const initialHeaders = {
202+
const headers = {
206203
'Content-Type': 'text/plain',
207204
'Content-Encoding': 'gzip',
208205
}
209-
210-
const headers = addProxyHeaders(envs, initialHeaders)
211206

212207
return {
213208
agent: addProxyIfNeeded(envs, args),

test/helpers/proxy.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { ProxyAgent } from 'undici'
2+
import { addProxyIfNeeded, getBasicAuthToken, removeUrlAuth } from '../../src/helpers/proxy'
3+
import { UploaderArgs } from '../../src/types'
4+
5+
describe('Proxy - getBasicAuthToken', () => {
6+
it('should make base64-encoded auth token from username and password', () => {
7+
const token = getBasicAuthToken('alice', 'pa$$w0rd')
8+
expect(token).toEqual('Basic YWxpY2U6cGEkJHcwcmQ=')
9+
})
10+
})
11+
12+
describe('Proxy - removeUrlAuth', () => {
13+
it('should remove auth data from url', () => {
14+
const proxyUrl = 'http://alice:[email protected]:1234/'
15+
expect(removeUrlAuth(proxyUrl)).toEqual('http://proxy.local:1234/')
16+
})
17+
})
18+
19+
// copied from undici sources, as not all of them are in module exports
20+
const kProxy = Symbol('proxy agent options')
21+
const kProxyHeaders = Symbol('proxy headers')
22+
const proxyAuthHeader = 'proxy-authorization'
23+
24+
// helper to get ProxyAgent property indexed with given Symbol
25+
function getAgentProperty(agent: ProxyAgent, property: Symbol): any {
26+
const originalSymbol = Reflect.ownKeys(agent).filter((item) => item.toString() === property.toString())?.[0]
27+
return originalSymbol ? Reflect.get(agent, originalSymbol) : undefined
28+
}
29+
30+
describe('Proxy - addProxyIfNeeded', () => {
31+
it.each([
32+
[''],
33+
['invalid'],
34+
])('should not return proxy if upstream argument is not set or invalid (%p)', (proxyUrl: string) => {
35+
const args: UploaderArgs = {
36+
flags: [],
37+
slug: '',
38+
upstream: proxyUrl,
39+
}
40+
41+
const proxy = addProxyIfNeeded({}, args)
42+
expect(proxy).toBeUndefined()
43+
})
44+
45+
it.each([
46+
['http://proxy.local:1234/', 'http://proxy.local:1234/', undefined],
47+
['http://alice:[email protected]:1234/', 'http://proxy.local:1234/', 'Basic YWxpY2U6cGEkJHcwcmQ='],
48+
])('should return proxy if upstream argument is set (%p)', (proxyUrl: string, expectedUri: string, expectedAuthHeader: any) => {
49+
const args: UploaderArgs = {
50+
flags: [],
51+
slug: '',
52+
upstream: proxyUrl,
53+
}
54+
55+
const proxy = addProxyIfNeeded({}, args)
56+
expect(proxy).toBeDefined()
57+
58+
const agentOptions = getAgentProperty(proxy as ProxyAgent, kProxy)
59+
expect(agentOptions?.['uri']).toEqual(expectedUri)
60+
61+
const agentHeaders = getAgentProperty(proxy as ProxyAgent, kProxyHeaders)
62+
expect(agentHeaders?.[proxyAuthHeader]).toEqual(expectedAuthHeader)
63+
})
64+
})

test/proxy.test.ts

Lines changed: 0 additions & 62 deletions
This file was deleted.

0 commit comments

Comments
 (0)