-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: use token param for upstream proxy auth
- Loading branch information
1 parent
acf4d83
commit b448744
Showing
4 changed files
with
97 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,37 @@ | ||
import { ProxyAgent } from 'undici'; | ||
import { UploaderArgs, UploaderEnvs } from '../types.js'; | ||
import { IncomingHttpHeaders } from 'undici/types/header.js'; | ||
import { logError } from './logger' | ||
|
||
export function addProxyIfNeeded(envs: UploaderEnvs, args: UploaderArgs): ProxyAgent | undefined { | ||
return args.upstream ? new ProxyAgent({ uri: args.upstream }) : undefined; | ||
export function getBasicAuthToken(username: string, password: string): string { | ||
const authString = Buffer.from(`${username}:${password}`).toString('base64') | ||
return `Basic ${authString}` | ||
} | ||
|
||
export function removeUrlAuth(url: string | URL): string { | ||
const noAuthUrl = new URL(url) | ||
noAuthUrl.username = '' | ||
noAuthUrl.password = '' | ||
return noAuthUrl.href | ||
} | ||
|
||
export function addProxyHeaders(envs: UploaderEnvs, initialHeaders: IncomingHttpHeaders): IncomingHttpHeaders { | ||
let headers: IncomingHttpHeaders | ||
if (envs['PROXY_BASIC_USER'] && envs['PROXY_BASIC_PASS']) { | ||
const authString = Buffer.from(`${envs['PROXY_BASIC_USER']}:${envs['PROXY_BASIC_PASS']}`).toString("base64") | ||
headers = { ...initialHeaders, Authorization: `Basic ${authString}` } | ||
} else { | ||
headers = initialHeaders | ||
export function addProxyIfNeeded(envs: UploaderEnvs, args: UploaderArgs): ProxyAgent | undefined { | ||
if (!args.upstream) { | ||
return undefined | ||
} | ||
return headers | ||
|
||
// https://github.com/nodejs/undici/blob/main/docs/api/ProxyAgent.md#example---basic-proxy-request-with-authentication | ||
try { | ||
const proxyUrl = new URL(args.upstream) | ||
if (proxyUrl.username && proxyUrl.password) { | ||
return new ProxyAgent({ | ||
uri: removeUrlAuth(proxyUrl), | ||
token: getBasicAuthToken(proxyUrl.username, proxyUrl.password), | ||
}) | ||
} | ||
return new ProxyAgent({ uri: args.upstream }) | ||
} catch (err) { | ||
logError(`Couldn't set upstream proxy: ${err}`) | ||
} | ||
|
||
return undefined | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { ProxyAgent } from 'undici' | ||
import { addProxyIfNeeded, getBasicAuthToken, removeUrlAuth } from '../../src/helpers/proxy' | ||
import { UploaderArgs } from '../../src/types' | ||
|
||
describe('Proxy - getBasicAuthToken', () => { | ||
it('should make base64-encoded auth token from username and password', () => { | ||
const token = getBasicAuthToken('alice', 'pa$$w0rd') | ||
expect(token).toEqual('Basic YWxpY2U6cGEkJHcwcmQ=') | ||
}) | ||
}) | ||
|
||
describe('Proxy - removeUrlAuth', () => { | ||
it('should remove auth data from url', () => { | ||
const proxyUrl = 'http://alice:[email protected]:1234/' | ||
expect(removeUrlAuth(proxyUrl)).toEqual('http://proxy.local:1234/') | ||
}) | ||
}) | ||
|
||
// copied from undici sources, as not all of them are in module exports | ||
const kProxy = Symbol('proxy agent options') | ||
const kProxyHeaders = Symbol('proxy headers') | ||
const proxyAuthHeader = 'proxy-authorization' | ||
|
||
// helper to get ProxyAgent property indexed with given Symbol | ||
function getAgentProperty(agent: ProxyAgent, property: Symbol): any { | ||
const originalSymbol = Reflect.ownKeys(agent).filter((item) => item.toString() === property.toString())?.[0] | ||
return originalSymbol ? Reflect.get(agent, originalSymbol) : undefined | ||
} | ||
|
||
describe('Proxy - addProxyIfNeeded', () => { | ||
it.each([ | ||
[''], | ||
['invalid'], | ||
])('should not return proxy if upstream argument is not set or invalid (%p)', (proxyUrl: string) => { | ||
const args: UploaderArgs = { | ||
flags: [], | ||
slug: '', | ||
upstream: proxyUrl, | ||
} | ||
|
||
const proxy = addProxyIfNeeded({}, args) | ||
expect(proxy).toBeUndefined() | ||
}) | ||
|
||
it.each([ | ||
['http://proxy.local:1234/', 'http://proxy.local:1234/', undefined], | ||
['http://alice:[email protected]:1234/', 'http://proxy.local:1234/', 'Basic YWxpY2U6cGEkJHcwcmQ='], | ||
])('should return proxy if upstream argument is set (%p)', (proxyUrl: string, expectedUri: string, expectedAuthHeader: any) => { | ||
const args: UploaderArgs = { | ||
flags: [], | ||
slug: '', | ||
upstream: proxyUrl, | ||
} | ||
|
||
const proxy = addProxyIfNeeded({}, args) | ||
expect(proxy).toBeDefined() | ||
|
||
const agentOptions = getAgentProperty(proxy as ProxyAgent, kProxy) | ||
expect(agentOptions?.['uri']).toEqual(expectedUri) | ||
|
||
const agentHeaders = getAgentProperty(proxy as ProxyAgent, kProxyHeaders) | ||
expect(agentHeaders?.[proxyAuthHeader]).toEqual(expectedAuthHeader) | ||
}) | ||
}) |
This file was deleted.
Oops, something went wrong.