mirror of
https://github.com/fallenbagel/jellyseerr.git
synced 2025-12-24 02:39:18 -05:00
With the update of undici to v7, the bypass list of addresses (no_proxy addresses) was not ignored anymore. fix #1454
114 lines
2.9 KiB
TypeScript
114 lines
2.9 KiB
TypeScript
import type { ProxySettings } from '@server/lib/settings';
|
|
import logger from '@server/logger';
|
|
import type { Dispatcher } from 'undici';
|
|
import { Agent, ProxyAgent, setGlobalDispatcher } from 'undici';
|
|
|
|
export default async function createCustomProxyAgent(
|
|
proxySettings: ProxySettings
|
|
) {
|
|
const defaultAgent = new Agent({ keepAliveTimeout: 5000 });
|
|
|
|
const skipUrl = (url: string | URL) => {
|
|
const hostname =
|
|
typeof url === 'string' ? new URL(url).hostname : url.hostname;
|
|
|
|
if (proxySettings.bypassLocalAddresses && isLocalAddress(hostname)) {
|
|
return true;
|
|
}
|
|
|
|
for (const address of proxySettings.bypassFilter.split(',')) {
|
|
const trimmedAddress = address.trim();
|
|
if (!trimmedAddress) {
|
|
continue;
|
|
}
|
|
|
|
if (trimmedAddress.startsWith('*')) {
|
|
const domain = trimmedAddress.slice(1);
|
|
if (hostname.endsWith(domain)) {
|
|
return true;
|
|
}
|
|
} else if (hostname === trimmedAddress) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
const noProxyInterceptor = (
|
|
dispatch: Dispatcher['dispatch']
|
|
): Dispatcher['dispatch'] => {
|
|
return (opts, handler) => {
|
|
return opts.origin && skipUrl(opts.origin)
|
|
? defaultAgent.dispatch(opts, handler)
|
|
: dispatch(opts, handler);
|
|
};
|
|
};
|
|
|
|
const token =
|
|
proxySettings.user && proxySettings.password
|
|
? `Basic ${Buffer.from(
|
|
`${proxySettings.user}:${proxySettings.password}`
|
|
).toString('base64')}`
|
|
: undefined;
|
|
|
|
try {
|
|
const proxyAgent = new ProxyAgent({
|
|
uri:
|
|
(proxySettings.useSsl ? 'https://' : 'http://') +
|
|
proxySettings.hostname +
|
|
':' +
|
|
proxySettings.port,
|
|
token,
|
|
keepAliveTimeout: 5000,
|
|
});
|
|
|
|
setGlobalDispatcher(proxyAgent.compose(noProxyInterceptor));
|
|
} catch (e) {
|
|
logger.error('Failed to connect to the proxy: ' + e.message, {
|
|
label: 'Proxy',
|
|
});
|
|
setGlobalDispatcher(defaultAgent);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const res = await fetch('https://www.google.com', { method: 'HEAD' });
|
|
if (res.ok) {
|
|
logger.debug('HTTP(S) proxy connected successfully', { label: 'Proxy' });
|
|
} else {
|
|
logger.error('Proxy responded, but with a non-OK status: ' + res.status, {
|
|
label: 'Proxy',
|
|
});
|
|
setGlobalDispatcher(defaultAgent);
|
|
}
|
|
} catch (e) {
|
|
logger.error(
|
|
'Failed to connect to the proxy: ' + e.message + ': ' + e.cause,
|
|
{ label: 'Proxy' }
|
|
);
|
|
setGlobalDispatcher(defaultAgent);
|
|
}
|
|
}
|
|
|
|
function isLocalAddress(hostname: string) {
|
|
if (
|
|
hostname === 'localhost' ||
|
|
hostname === '127.0.0.1' ||
|
|
hostname === '::1'
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
const privateIpRanges = [
|
|
/^10\./, // 10.x.x.x
|
|
/^172\.(1[6-9]|2[0-9]|3[0-1])\./, // 172.16.x.x - 172.31.x.x
|
|
/^192\.168\./, // 192.168.x.x
|
|
];
|
|
if (privateIpRanges.some((regex) => regex.test(hostname))) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|