|
|
const { SocksProxyAgent } = require('socks-proxy-agent') |
|
|
const { HttpsProxyAgent } = require('https-proxy-agent') |
|
|
const logger = require('./logger') |
|
|
const config = require('../../config/config') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ProxyHelper { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static createProxyAgent(proxyConfig, options = {}) { |
|
|
if (!proxyConfig) { |
|
|
return null |
|
|
} |
|
|
|
|
|
try { |
|
|
|
|
|
const proxy = typeof proxyConfig === 'string' ? JSON.parse(proxyConfig) : proxyConfig |
|
|
|
|
|
|
|
|
if (!proxy.type || !proxy.host || !proxy.port) { |
|
|
logger.warn('⚠️ Invalid proxy configuration: missing required fields (type, host, port)') |
|
|
return null |
|
|
} |
|
|
|
|
|
|
|
|
const useIPv4 = ProxyHelper._getIPFamilyPreference(options.useIPv4) |
|
|
|
|
|
|
|
|
const auth = proxy.username && proxy.password ? `${proxy.username}:${proxy.password}@` : '' |
|
|
|
|
|
|
|
|
if (proxy.type === 'socks5') { |
|
|
const socksUrl = `socks5h://${auth}${proxy.host}:${proxy.port}` |
|
|
const socksOptions = {} |
|
|
|
|
|
|
|
|
if (useIPv4 !== null) { |
|
|
socksOptions.family = useIPv4 ? 4 : 6 |
|
|
} |
|
|
|
|
|
return new SocksProxyAgent(socksUrl, socksOptions) |
|
|
} else if (proxy.type === 'http' || proxy.type === 'https') { |
|
|
const proxyUrl = `${proxy.type}://${auth}${proxy.host}:${proxy.port}` |
|
|
const httpOptions = {} |
|
|
|
|
|
|
|
|
if (useIPv4 !== null) { |
|
|
httpOptions.family = useIPv4 ? 4 : 6 |
|
|
} |
|
|
|
|
|
return new HttpsProxyAgent(proxyUrl, httpOptions) |
|
|
} else { |
|
|
logger.warn(`⚠️ Unsupported proxy type: ${proxy.type}`) |
|
|
return null |
|
|
} |
|
|
} catch (error) { |
|
|
logger.warn('⚠️ Failed to create proxy agent:', error.message) |
|
|
return null |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static _getIPFamilyPreference(preference) { |
|
|
|
|
|
if (preference === undefined) { |
|
|
|
|
|
const defaultUseIPv4 = config.proxy?.useIPv4 |
|
|
if (defaultUseIPv4 !== undefined) { |
|
|
return defaultUseIPv4 |
|
|
} |
|
|
|
|
|
return true |
|
|
} |
|
|
|
|
|
|
|
|
if (typeof preference === 'boolean') { |
|
|
return preference |
|
|
} |
|
|
if (typeof preference === 'number') { |
|
|
return preference === 4 ? true : preference === 6 ? false : null |
|
|
} |
|
|
if (typeof preference === 'string') { |
|
|
const lower = preference.toLowerCase() |
|
|
if (lower === 'ipv4' || lower === '4') { |
|
|
return true |
|
|
} |
|
|
if (lower === 'ipv6' || lower === '6') { |
|
|
return false |
|
|
} |
|
|
if (lower === 'auto' || lower === 'both') { |
|
|
return null |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return true |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static validateProxyConfig(proxyConfig) { |
|
|
if (!proxyConfig) { |
|
|
return false |
|
|
} |
|
|
|
|
|
try { |
|
|
const proxy = typeof proxyConfig === 'string' ? JSON.parse(proxyConfig) : proxyConfig |
|
|
|
|
|
|
|
|
if (!proxy.type || !proxy.host || !proxy.port) { |
|
|
return false |
|
|
} |
|
|
|
|
|
|
|
|
if (!['socks5', 'http', 'https'].includes(proxy.type)) { |
|
|
return false |
|
|
} |
|
|
|
|
|
|
|
|
const port = parseInt(proxy.port) |
|
|
if (isNaN(port) || port < 1 || port > 65535) { |
|
|
return false |
|
|
} |
|
|
|
|
|
return true |
|
|
} catch (error) { |
|
|
return false |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static getProxyDescription(proxyConfig) { |
|
|
if (!proxyConfig) { |
|
|
return 'No proxy' |
|
|
} |
|
|
|
|
|
try { |
|
|
const proxy = typeof proxyConfig === 'string' ? JSON.parse(proxyConfig) : proxyConfig |
|
|
const hasAuth = proxy.username && proxy.password |
|
|
return `${proxy.type}://${proxy.host}:${proxy.port}${hasAuth ? ' (with auth)' : ''}` |
|
|
} catch (error) { |
|
|
return 'Invalid proxy config' |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static maskProxyInfo(proxyConfig) { |
|
|
if (!proxyConfig) { |
|
|
return 'No proxy' |
|
|
} |
|
|
|
|
|
try { |
|
|
const proxy = typeof proxyConfig === 'string' ? JSON.parse(proxyConfig) : proxyConfig |
|
|
|
|
|
let proxyDesc = `${proxy.type}://${proxy.host}:${proxy.port}` |
|
|
|
|
|
|
|
|
if (proxy.username && proxy.password) { |
|
|
const maskedUsername = |
|
|
proxy.username.length <= 2 |
|
|
? proxy.username |
|
|
: proxy.username[0] + |
|
|
'*'.repeat(Math.max(1, proxy.username.length - 2)) + |
|
|
proxy.username.slice(-1) |
|
|
const maskedPassword = '*'.repeat(Math.min(8, proxy.password.length)) |
|
|
proxyDesc += ` (auth: ${maskedUsername}:${maskedPassword})` |
|
|
} |
|
|
|
|
|
return proxyDesc |
|
|
} catch (error) { |
|
|
return 'Invalid proxy config' |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static createProxy(proxyConfig, useIPv4 = true) { |
|
|
logger.warn('⚠️ ProxyHelper.createProxy is deprecated, use createProxyAgent instead') |
|
|
return ProxyHelper.createProxyAgent(proxyConfig, { useIPv4 }) |
|
|
} |
|
|
} |
|
|
|
|
|
module.exports = ProxyHelper |
|
|
|