1"use strict"; 2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 if (k2 === undefined) k2 = k; 4 var desc = Object.getOwnPropertyDescriptor(m, k); 5 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 desc = { enumerable: true, get: function() { return m[k]; } }; 7 } 8 Object.defineProperty(o, k2, desc); 9}) : (function(o, m, k, k2) { 10 if (k2 === undefined) k2 = k; 11 o[k2] = m[k]; 12})); 13var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 Object.defineProperty(o, "default", { enumerable: true, value: v }); 15}) : function(o, v) { 16 o["default"] = v; 17}); 18var __importStar = (this && this.__importStar) || function (mod) { 19 if (mod && mod.__esModule) return mod; 20 var result = {}; 21 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 __setModuleDefault(result, mod); 23 return result; 24}; 25var __importDefault = (this && this.__importDefault) || function (mod) { 26 return (mod && mod.__esModule) ? mod : { "default": mod }; 27}; 28Object.defineProperty(exports, "__esModule", { value: true }); 29exports.SocksProxyAgent = void 0; 30const socks_1 = require("socks"); 31const agent_base_1 = require("agent-base"); 32const debug_1 = __importDefault(require("debug")); 33const dns = __importStar(require("dns")); 34const net = __importStar(require("net")); 35const tls = __importStar(require("tls")); 36const url_1 = require("url"); 37const debug = (0, debug_1.default)('socks-proxy-agent'); 38function parseSocksURL(url) { 39 let lookup = false; 40 let type = 5; 41 const host = url.hostname; 42 // From RFC 1928, Section 3: https://tools.ietf.org/html/rfc1928#section-3 43 // "The SOCKS service is conventionally located on TCP port 1080" 44 const port = parseInt(url.port, 10) || 1080; 45 // figure out if we want socks v4 or v5, based on the "protocol" used. 46 // Defaults to 5. 47 switch (url.protocol.replace(':', '')) { 48 case 'socks4': 49 lookup = true; 50 type = 4; 51 break; 52 // pass through 53 case 'socks4a': 54 type = 4; 55 break; 56 case 'socks5': 57 lookup = true; 58 type = 5; 59 break; 60 // pass through 61 case 'socks': // no version specified, default to 5h 62 type = 5; 63 break; 64 case 'socks5h': 65 type = 5; 66 break; 67 default: 68 throw new TypeError(`A "socks" protocol must be specified! Got: ${String(url.protocol)}`); 69 } 70 const proxy = { 71 host, 72 port, 73 type, 74 }; 75 if (url.username) { 76 Object.defineProperty(proxy, 'userId', { 77 value: decodeURIComponent(url.username), 78 enumerable: false, 79 }); 80 } 81 if (url.password != null) { 82 Object.defineProperty(proxy, 'password', { 83 value: decodeURIComponent(url.password), 84 enumerable: false, 85 }); 86 } 87 return { lookup, proxy }; 88} 89class SocksProxyAgent extends agent_base_1.Agent { 90 constructor(uri, opts) { 91 super(opts); 92 const url = typeof uri === 'string' ? new url_1.URL(uri) : uri; 93 const { proxy, lookup } = parseSocksURL(url); 94 this.shouldLookup = lookup; 95 this.proxy = proxy; 96 this.timeout = opts?.timeout ?? null; 97 } 98 /** 99 * Initiates a SOCKS connection to the specified SOCKS proxy server, 100 * which in turn connects to the specified remote host and port. 101 */ 102 async connect(req, opts) { 103 const { shouldLookup, proxy, timeout } = this; 104 if (!opts.host) { 105 throw new Error('No `host` defined!'); 106 } 107 let { host } = opts; 108 const { port, lookup: lookupFn = dns.lookup } = opts; 109 if (shouldLookup) { 110 // Client-side DNS resolution for "4" and "5" socks proxy versions. 111 host = await new Promise((resolve, reject) => { 112 // Use the request's custom lookup, if one was configured: 113 lookupFn(host, {}, (err, res) => { 114 if (err) { 115 reject(err); 116 } 117 else { 118 resolve(res); 119 } 120 }); 121 }); 122 } 123 const socksOpts = { 124 proxy, 125 destination: { 126 host, 127 port: typeof port === 'number' ? port : parseInt(port, 10), 128 }, 129 command: 'connect', 130 timeout: timeout ?? undefined, 131 }; 132 const cleanup = (tlsSocket) => { 133 req.destroy(); 134 socket.destroy(); 135 if (tlsSocket) 136 tlsSocket.destroy(); 137 }; 138 debug('Creating socks proxy connection: %o', socksOpts); 139 const { socket } = await socks_1.SocksClient.createConnection(socksOpts); 140 debug('Successfully created socks proxy connection'); 141 if (timeout !== null) { 142 socket.setTimeout(timeout); 143 socket.on('timeout', () => cleanup()); 144 } 145 if (opts.secureEndpoint) { 146 // The proxy is connecting to a TLS server, so upgrade 147 // this socket connection to a TLS connection. 148 debug('Upgrading socket connection to TLS'); 149 const servername = opts.servername || opts.host; 150 const tlsSocket = tls.connect({ 151 ...omit(opts, 'host', 'path', 'port'), 152 socket, 153 servername: net.isIP(servername) ? undefined : servername, 154 }); 155 tlsSocket.once('error', (error) => { 156 debug('Socket TLS error', error.message); 157 cleanup(tlsSocket); 158 }); 159 return tlsSocket; 160 } 161 return socket; 162 } 163} 164SocksProxyAgent.protocols = [ 165 'socks', 166 'socks4', 167 'socks4a', 168 'socks5', 169 'socks5h', 170]; 171exports.SocksProxyAgent = SocksProxyAgent; 172function omit(obj, ...keys) { 173 const ret = {}; 174 let key; 175 for (key in obj) { 176 if (!keys.includes(key)) { 177 ret[key] = obj[key]; 178 } 179 } 180 return ret; 181} 182//# sourceMappingURL=index.js.map