UNPKG

@rynn-k/proxy-agent

Version:

Efficient proxy rotation agent for Node.js with seamless axios integration

198 lines (165 loc) 4.84 kB
const net = require('net'); /** * Validate IP address * @param {string} ip - IP address to validate * @returns {boolean} True if valid IP */ function isValidIP(ip) { return net.isIP(ip) !== 0; } /** * Validate port number * @param {string|number} port - Port to validate * @returns {boolean} True if valid port */ function isValidPort(port) { const portNum = parseInt(port, 10); return !isNaN(portNum) && portNum > 0 && portNum <= 65535; } /** * Validate proxy object * @param {Object} proxy - Proxy object to validate * @returns {boolean} True if valid proxy */ function validateProxy(proxy) { if (!proxy || typeof proxy !== 'object') { return false; } if (!proxy.ip || !proxy.port) { return false; } if (!isValidIP(proxy.ip)) { return false; } if (!isValidPort(proxy.port)) { return false; } // If authentication is provided, validate it if (proxy.username || proxy.password) { if (!proxy.username || !proxy.password) { return false; // Both username and password required } if (typeof proxy.username !== 'string' || typeof proxy.password !== 'string') { return false; } if (proxy.username.length === 0 || proxy.password.length === 0) { return false; } } return true; } /** * Parse proxy line from file * @param {string} line - Proxy line from file * @param {number} lineNumber - Line number for error reporting * @returns {Object} Parsed proxy object */ function parseProxyLine(line, lineNumber = 0) { const parts = line.trim().split(':'); if (parts.length < 2) { throw new Error(`Invalid proxy format at line ${lineNumber}: expected at least ip:port`); } const ip = parts[0].trim(); const port = parts[1].trim(); if (!ip || !port) { throw new Error(`Empty IP or port at line ${lineNumber}`); } // Basic proxy without authentication if (parts.length === 2) { return { ip, port: parseInt(port, 10), url: `http://${ip}:${port}`, protocol: 'http' }; } // Proxy with authentication if (parts.length === 4) { const username = parts[2].trim(); const password = parts[3].trim(); if (!username || !password) { throw new Error(`Empty username or password at line ${lineNumber}`); } // URL encode credentials to handle special characters const encodedUsername = encodeURIComponent(username); const encodedPassword = encodeURIComponent(password); return { ip, port: parseInt(port, 10), username, password, url: `http://${encodedUsername}:${encodedPassword}@${ip}:${port}`, protocol: 'http' }; } // Handle protocol:ip:port format if (parts.length === 3) { const protocol = parts[0].toLowerCase(); const ipPart = parts[1]; const portPart = parts[2]; if (!['http', 'https', 'socks4', 'socks5'].includes(protocol)) { throw new Error(`Unsupported protocol '${protocol}' at line ${lineNumber}`); } return { ip: ipPart, port: parseInt(portPart, 10), url: `${protocol}://${ipPart}:${portPart}`, protocol }; } // Handle protocol:ip:port:username:password format if (parts.length === 5) { const protocol = parts[0].toLowerCase(); const ipPart = parts[1]; const portPart = parts[2]; const username = parts[3].trim(); const password = parts[4].trim(); if (!['http', 'https', 'socks4', 'socks5'].includes(protocol)) { throw new Error(`Unsupported protocol '${protocol}' at line ${lineNumber}`); } if (!username || !password) { throw new Error(`Empty username or password at line ${lineNumber}`); } const encodedUsername = encodeURIComponent(username); const encodedPassword = encodeURIComponent(password); return { ip: ipPart, port: parseInt(portPart, 10), username, password, url: `${protocol}://${encodedUsername}:${encodedPassword}@${ipPart}:${portPart}`, protocol }; } throw new Error(`Invalid proxy format at line ${lineNumber}: unsupported format with ${parts.length} parts`); } /** * Parse proxy URL * @param {string} proxyUrl - Proxy URL to parse * @returns {Object} Parsed proxy object */ function parseProxyUrl(proxyUrl) { try { const url = new URL(proxyUrl); const proxy = { ip: url.hostname, port: parseInt(url.port, 10), protocol: url.protocol.replace(':', ''), url: proxyUrl }; if (url.username && url.password) { proxy.username = decodeURIComponent(url.username); proxy.password = decodeURIComponent(url.password); } return proxy; } catch (error) { throw new Error(`Invalid proxy URL: ${error.message}`); } } module.exports = { isValidIP, isValidPort, validateProxy, parseProxyLine, parseProxyUrl };