pax_global_header00006660000000000000000000000064142454215060014515gustar00rootroot0000000000000052 comment=c178516b85c618f308bb4fd0002878c9dc5d9824 node-socks-proxy-agent-7.0.0/000077500000000000000000000000001424542150600160415ustar00rootroot00000000000000node-socks-proxy-agent-7.0.0/.editorconfig000066400000000000000000000005551424542150600205230ustar00rootroot00000000000000# http://editorconfig.org root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true max_line_length = 100 indent_brace_style = 1TBS spaces_around_operators = true quote_type = auto [package.json] indent_style = space indent_size = 2 [*.md] trim_trailing_whitespace = false node-socks-proxy-agent-7.0.0/.github/000077500000000000000000000000001424542150600174015ustar00rootroot00000000000000node-socks-proxy-agent-7.0.0/.github/dependabot.yml000066400000000000000000000004011424542150600222240ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: npm directory: "/" schedule: interval: daily - package-ecosystem: "github-actions" directory: "/" schedule: # Check for updates to GitHub Actions every weekday interval: "daily" node-socks-proxy-agent-7.0.0/.github/workflows/000077500000000000000000000000001424542150600214365ustar00rootroot00000000000000node-socks-proxy-agent-7.0.0/.github/workflows/test.yml000066400000000000000000000015741424542150600231470ustar00rootroot00000000000000name: Node CI on: push: branches: - master tags: - '!*' pull_request: jobs: build: name: Test Node.js ${{ matrix.node-version }} on ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] node-version: [10.x, 12.x, 14.x, 16.x] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - name: Print Node.js Version run: node --version - name: Install Dependencies run: npm install env: CI: true - name: Run "build" step run: npm run build --if-present env: CI: true - name: Run tests run: npm run test env: CI: true node-socks-proxy-agent-7.0.0/.gitignore000066400000000000000000000001671424542150600200350ustar00rootroot00000000000000/node_modules /?.?s /dist # mac files *.DS_Store # vim temp files *.sw? /yarn.lock /package-lock.json # env .envrc node-socks-proxy-agent-7.0.0/CHANGELOG.md000066400000000000000000000025361424542150600176600ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. ## [7.0.0](https://github.com/TooTallNate/node-socks-proxy-agent/compare/v6.2.1...v7.0.0) (2022-05-31) ### Features * remove host support ([#97](https://github.com/TooTallNate/node-socks-proxy-agent/issues/97)) ([fcc3108](https://github.com/TooTallNate/node-socks-proxy-agent/commit/fcc310836fa29d16e3351f98cfdf57403a95591e)) ### [6.2.1](https://github.com/TooTallNate/node-socks-proxy-agent/compare/v6.2.0...v6.2.1) (2022-05-31) ### Bug Fixes * make opts.host work again ([#96](https://github.com/TooTallNate/node-socks-proxy-agent/issues/96)) ([eb87f6c](https://github.com/TooTallNate/node-socks-proxy-agent/commit/eb87f6c27b06a85825df9a8ac8ef133d66566058)) ## [6.2.0](https://github.com/TooTallNate/node-socks-proxy-agent/compare/v6.2.0-beta.1...v6.2.0) (2022-04-17) ## [6.2.0-beta.1](https://github.com/TooTallNate/node-socks-proxy-agent/compare/v6.2.0-beta.0...v6.2.0-beta.1) (2022-02-15) ## [6.2.0-beta.0](https://github.com/TooTallNate/node-socks-proxy-agent/compare/v6.1.1...v6.2.0-beta.0) (2022-02-12) ### Bug Fixes * **linter:** not allowed space ([c55cc77](https://github.com/TooTallNate/node-socks-proxy-agent/commit/c55cc777dbda6f98975d7229da6a4aa53f38e17b)) node-socks-proxy-agent-7.0.0/README.md000066400000000000000000000107511424542150600173240ustar00rootroot00000000000000socks-proxy-agent ================ ### A SOCKS proxy `http.Agent` implementation for HTTP and HTTPS [![Build Status](https://github.com/TooTallNate/node-socks-proxy-agent/workflows/Node%20CI/badge.svg)](https://github.com/TooTallNate/node-socks-proxy-agent/actions?workflow=Node+CI) This module provides an `http.Agent` implementation that connects to a specified SOCKS proxy server, and can be used with the built-in `http` and `https` modules. It can also be used in conjunction with the `ws` module to establish a WebSocket connection over a SOCKS proxy. See the "Examples" section below. Installation ------------ Install with `npm`: ``` bash npm install socks-proxy-agent ``` Examples -------- #### TypeScript example ```ts import https from 'https'; import { SocksProxyAgent } from 'socks-proxy-agent'; const info = { hostname: 'br41.nordvpn.com', userId: 'your-name@gmail.com', password: 'abcdef12345124' }; const agent = new SocksProxyAgent(info); https.get('https://ipinfo.io', { agent }, (res) => { console.log(res.headers); res.pipe(process.stdout); }); ``` #### `http` module example ```js var url = require('url'); var http = require('http'); var { SocksProxyAgent } = require('socks-proxy-agent'); // SOCKS proxy to connect to var proxy = process.env.socks_proxy || 'socks://127.0.0.1:1080'; console.log('using proxy server %j', proxy); // HTTP endpoint for the proxy to connect to var endpoint = process.argv[2] || 'http://nodejs.org/api/'; console.log('attempting to GET %j', endpoint); var opts = url.parse(endpoint); // create an instance of the `SocksProxyAgent` class with the proxy server information var agent = new SocksProxyAgent(proxy); opts.agent = agent; http.get(opts, function (res) { console.log('"response" event!', res.headers); res.pipe(process.stdout); }); ``` #### `https` module example ```js var url = require('url'); var https = require('https'); var { SocksProxyAgent } = require('socks-proxy-agent'); // SOCKS proxy to connect to var proxy = process.env.socks_proxy || 'socks://127.0.0.1:1080'; console.log('using proxy server %j', proxy); // HTTP endpoint for the proxy to connect to var endpoint = process.argv[2] || 'https://encrypted.google.com/'; console.log('attempting to GET %j', endpoint); var opts = url.parse(endpoint); // create an instance of the `SocksProxyAgent` class with the proxy server information var agent = new SocksProxyAgent(proxy); opts.agent = agent; https.get(opts, function (res) { console.log('"response" event!', res.headers); res.pipe(process.stdout); }); ``` #### `ws` WebSocket connection example ``` js var WebSocket = require('ws'); var { SocksProxyAgent } = require('socks-proxy-agent'); // SOCKS proxy to connect to var proxy = process.env.socks_proxy || 'socks://127.0.0.1:1080'; console.log('using proxy server %j', proxy); // WebSocket endpoint for the proxy to connect to var endpoint = process.argv[2] || 'ws://echo.websocket.org'; console.log('attempting to connect to WebSocket %j', endpoint); // create an instance of the `SocksProxyAgent` class with the proxy server information var agent = new SocksProxyAgent(proxy); // initiate the WebSocket connection var socket = new WebSocket(endpoint, { agent: agent }); socket.on('open', function () { console.log('"open" event!'); socket.send('hello world'); }); socket.on('message', function (data, flags) { console.log('"message" event! %j %j', data, flags); socket.close(); }); ``` License ------- (The MIT License) Copyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. node-socks-proxy-agent-7.0.0/package.json000066400000000000000000000105631424542150600203340ustar00rootroot00000000000000{ "name": "socks-proxy-agent", "description": "A SOCKS proxy `http.Agent` implementation for HTTP and HTTPS", "homepage": "https://github.com/TooTallNate/node-socks-proxy-agent#readme", "version": "7.0.0", "main": "dist/index.js", "author": { "email": "nathan@tootallnate.net", "name": "Nathan Rajlich", "url": "http://n8.io/" }, "contributors": [ { "name": "Kiko Beats", "email": "josefrancisco.verdu@gmail.com" }, { "name": "Josh Glazebrook", "email": "josh@joshglazebrook.com" }, { "name": "talmobi", "email": "talmobi@users.noreply.github.com" }, { "name": "Indospace.io", "email": "justin@indospace.io" }, { "name": "Kilian von Pflugk", "email": "github@jumoog.io" }, { "name": "Kyle", "email": "admin@hk1229.cn" }, { "name": "Matheus Fernandes", "email": "matheus.frndes@gmail.com" }, { "name": "Ricky Miller", "email": "richardkazuomiller@gmail.com" }, { "name": "Shantanu Sharma", "email": "shantanu34@outlook.com" }, { "name": "Tim Perry", "email": "pimterry@gmail.com" }, { "name": "Vadim Baryshev", "email": "vadimbaryshev@gmail.com" }, { "name": "jigu", "email": "luo1257857309@gmail.com" }, { "name": "Alba Mendez", "email": "me@jmendeth.com" }, { "name": "Дмитрий Гуденков", "email": "Dimangud@rambler.ru" }, { "name": "Andrei Bitca", "email": "63638922+andrei-bitca-dc@users.noreply.github.com" }, { "name": "Andrew Casey", "email": "amcasey@users.noreply.github.com" }, { "name": "Brandon Ros", "email": "brandonros1@gmail.com" }, { "name": "Dang Duy Thanh", "email": "thanhdd.it@gmail.com" }, { "name": "Dimitar Nestorov", "email": "8790386+dimitarnestorov@users.noreply.github.com" } ], "repository": { "type": "git", "url": "git://github.com/TooTallNate/node-socks-proxy-agent.git" }, "bugs": { "url": "https://github.com/TooTallNate/node-socks-proxy-agent/issues" }, "keywords": [ "agent", "http", "https", "proxy", "socks", "socks4", "socks4a", "socks5", "socks5h" ], "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", "socks": "^2.6.2" }, "devDependencies": { "@commitlint/cli": "latest", "@commitlint/config-conventional": "latest", "@types/debug": "latest", "@types/node": "latest", "cacheable-lookup": "latest", "conventional-github-releaser": "latest", "dns2": "latest", "finepack": "latest", "git-authors-cli": "latest", "mocha": "9", "nano-staged": "latest", "npm-check-updates": "latest", "prettier-standard": "latest", "raw-body": "latest", "rimraf": "latest", "simple-git-hooks": "latest", "socksv5": "github:TooTallNate/socksv5#fix/dstSock-close-event", "standard": "latest", "standard-markdown": "latest", "standard-version": "latest", "ts-standard": "latest", "typescript": "latest" }, "engines": { "node": ">= 10" }, "files": [ "dist" ], "scripts": { "build": "tsc", "clean": "rimraf node_modules", "contributors": "(git-authors-cli && finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true", "lint": "ts-standard", "postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)", "prebuild": "rimraf dist", "prepublishOnly": "npm run build", "prerelease": "npm run update:check && npm run contributors", "release": "standard-version -a", "release:github": "conventional-github-releaser -p angular", "release:tags": "git push --follow-tags origin HEAD:master", "test": "mocha --reporter spec", "update": "ncu -u", "update:check": "ncu -- --error-level 2" }, "license": "MIT", "commitlint": { "extends": [ "@commitlint/config-conventional" ] }, "nano-staged": { "*.js": [ "prettier-standard" ], "*.md": [ "standard-markdown" ], "package.json": [ "finepack" ] }, "simple-git-hooks": { "commit-msg": "npx commitlint --edit", "pre-commit": "npx nano-staged" }, "typings": "dist/index.d.ts" } node-socks-proxy-agent-7.0.0/src/000077500000000000000000000000001424542150600166305ustar00rootroot00000000000000node-socks-proxy-agent-7.0.0/src/index.ts000066400000000000000000000140451424542150600203130ustar00rootroot00000000000000import { SocksClient, SocksProxy, SocksClientOptions } from 'socks' import { Agent, ClientRequest, RequestOptions } from 'agent-base' import { AgentOptions } from 'agent-base'; import createDebug from 'debug' import { Url } from 'url' import dns from 'dns' import net from 'net' import tls from 'tls' interface BaseSocksProxyAgentOptions { host?: string | null; port?: string | number | null; username?: string | null; tls?: tls.ConnectionOptions | null; } interface SocksProxyAgentOptionsExtra { timeout?: number } const debug = createDebug('socks-proxy-agent') function parseSocksProxy (opts: SocksProxyAgentOptions): { lookup: boolean, proxy: SocksProxy } { let port = 0 let lookup = false let type: SocksProxy['type'] = 5 const host = opts.hostname if (host == null) { throw new TypeError('No "host"') } if (typeof opts.port === 'number') { port = opts.port } else if (typeof opts.port === 'string') { port = parseInt(opts.port, 10) } // From RFC 1928, Section 3: https://tools.ietf.org/html/rfc1928#section-3 // "The SOCKS service is conventionally located on TCP port 1080" if (port == null) { port = 1080 } // figure out if we want socks v4 or v5, based on the "protocol" used. // Defaults to 5. if (opts.protocol != null) { switch (opts.protocol.replace(':', '')) { case 'socks4': lookup = true // pass through case 'socks4a': type = 4 break case 'socks5': lookup = true // pass through case 'socks': // no version specified, default to 5h case 'socks5h': type = 5 break default: throw new TypeError(`A "socks" protocol must be specified! Got: ${String(opts.protocol)}`) } } if (typeof opts.type !== 'undefined') { if (opts.type === 4 || opts.type === 5) { type = opts.type } else { throw new TypeError(`"type" must be 4 or 5, got: ${String(opts.type)}`) } } const proxy: SocksProxy = { host, port, type } let userId = opts.userId ?? opts.username let password = opts.password if (opts.auth != null) { const auth = opts.auth.split(':') userId = auth[0] password = auth[1] } if (userId != null) { Object.defineProperty(proxy, 'userId', { value: userId, enumerable: false }) } if (password != null) { Object.defineProperty(proxy, 'password', { value: password, enumerable: false }) } return { lookup, proxy } } const normalizeProxyOptions = (input: string | SocksProxyAgentOptions): SocksProxyAgentOptions => { let proxyOptions: SocksProxyAgentOptions if (typeof input === 'string') { proxyOptions = new URL(input) } else { proxyOptions = input } if (proxyOptions == null) { throw new TypeError('a SOCKS proxy server `host` and `port` must be specified!') } return proxyOptions } export interface SocksProxyAgentOptions extends AgentOptions, BaseSocksProxyAgentOptions, Partial> {} export class SocksProxyAgent extends Agent { private readonly shouldLookup: boolean private readonly proxy: SocksProxy private readonly tlsConnectionOptions: tls.ConnectionOptions public timeout: number | null constructor (input: string | SocksProxyAgentOptions, options?: SocksProxyAgentOptionsExtra) { const proxyOptions = normalizeProxyOptions(input) super(proxyOptions) const parsedProxy = parseSocksProxy(proxyOptions) this.shouldLookup = parsedProxy.lookup this.proxy = parsedProxy.proxy this.tlsConnectionOptions = proxyOptions.tls != null ? proxyOptions.tls : {} this.timeout = options?.timeout ?? null } /** * Initiates a SOCKS connection to the specified SOCKS proxy server, * which in turn connects to the specified remote host and port. * * @api protected */ async callback (req: ClientRequest, opts: RequestOptions): Promise { const { shouldLookup, proxy, timeout } = this let { host, port, lookup: lookupCallback } = opts if (host == null) { throw new Error('No `host` defined!') } if (shouldLookup) { // Client-side DNS resolution for "4" and "5" socks proxy versions. host = await new Promise((resolve, reject) => { // Use the request's custom lookup, if one was configured: const lookupFn = lookupCallback ?? dns.lookup lookupFn(host!, {}, (err, res) => { if (err) { reject(err) } else { resolve(res) } }) }) } const socksOpts: SocksClientOptions = { proxy, destination: { host, port }, command: 'connect', timeout: timeout ?? undefined } const cleanup = (tlsSocket?: tls.TLSSocket) => { req.destroy() socket.destroy() if (tlsSocket) tlsSocket.destroy() } debug('Creating socks proxy connection: %o', socksOpts) const { socket } = await SocksClient.createConnection(socksOpts) debug('Successfully created socks proxy connection') if (timeout !== null) { socket.setTimeout(timeout) socket.on('timeout', () => cleanup()) } if (opts.secureEndpoint) { // The proxy is connecting to a TLS server, so upgrade // this socket connection to a TLS connection. debug('Upgrading socket connection to TLS') const servername = opts.servername ?? opts.host const tlsSocket = tls.connect({ ...omit(opts, 'host', 'hostname', 'path', 'port'), socket, servername, ...this.tlsConnectionOptions }) tlsSocket.once('error', (error) => { debug('socket TLS error', error.message) cleanup(tlsSocket) }) return tlsSocket } return socket } } function omit]> ( obj: T, ...keys: K ): { [K2 in Exclude]: T[K2] } { const ret = {} as { [K in keyof typeof obj]: typeof obj[K] } let key: keyof typeof obj for (key in obj) { if (!keys.includes(key)) { ret[key] = obj[key] } } return ret } node-socks-proxy-agent-7.0.0/test/000077500000000000000000000000001424542150600170205ustar00rootroot00000000000000node-socks-proxy-agent-7.0.0/test/ssl-cert-snakeoil.key000066400000000000000000000015671424542150600231020ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQCzURxIqzer0ACAbX/lHdsn4Gd9PLKrf7EeDYfIdV0HZKPD8WDr bBx2/fBu0OW2sjnzv/SVZbJ0DAuPE/p0+eT0qb2qC10iz9iTD7ribd7gxhirVb8y b3fBjXsxc8V8p4Ny1LcvNSqCjwUbJqdRogfoJeTiqPM58z5sNzuv5iq7iwIDAQAB AoGAPMQy4olrP0UotlzlJ36bowLP70ffgHCwU+/f4NWs5fF78c3du0oSx1w820Dd Z7E0JF8bgnlJJTxjumPZz0RUCugrEHBKJmzEz3cxF5E3+7NvteZcjKn9D67RrM5x 1/uSZ9cqKE9cYvY4fSuHx18diyZ4axR/wB1Pea2utjjDM+ECQQDb9ZbmmaWMiRpQ 5Up+loxP7BZNPsEVsm+DVJmEFbaFgGfncWBqSIqnPNjMwTwj0OigTwCAEGPkfRVW T0pbYWCxAkEA0LK7SCTwzyDmhASUalk0x+3uCAA6ryFdwJf/wd8TRAvVOmkTEldX uJ7ldLvfrONYO3v56uKTU/SoNdZYzKtO+wJAX2KM4ctXYy5BXztPpr2acz4qHa1N Bh+vBAC34fOYhyQ76r3b1btHhWZ5jbFuZwm9F2erC94Ps5IaoqcX07DSwQJAPKGw h2U0EPkd/3zVIZCJJQya+vgWFIs9EZcXVtvYXQyTBkVApTN66MhBIYjzkub5205J bVQmOV37AKklY1DhwQJAA1wos0cYxro02edzatxd0DIR2r4qqOqLkw6BhYHhq6HJ ZvIcQkHqdSXzdETFc01I1znDGGIrJHcnvKWgBPoEUg== -----END RSA PRIVATE KEY----- node-socks-proxy-agent-7.0.0/test/ssl-cert-snakeoil.pem000066400000000000000000000012701424542150600230620ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB1TCCAT4CCQDV5mPlzm9+izANBgkqhkiG9w0BAQUFADAvMS0wKwYDVQQDEyQ3 NTI3YmQ3Ny1hYjNlLTQ3NGItYWNlNy1lZWQ2MDUzOTMxZTcwHhcNMTUwNzA2MjI0 NTA3WhcNMjUwNzAzMjI0NTA3WjAvMS0wKwYDVQQDEyQ3NTI3YmQ3Ny1hYjNlLTQ3 NGItYWNlNy1lZWQ2MDUzOTMxZTcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB ALNRHEirN6vQAIBtf+Ud2yfgZ308sqt/sR4Nh8h1XQdko8PxYOtsHHb98G7Q5bay OfO/9JVlsnQMC48T+nT55PSpvaoLXSLP2JMPuuJt3uDGGKtVvzJvd8GNezFzxXyn g3LUty81KoKPBRsmp1GiB+gl5OKo8znzPmw3O6/mKruLAgMBAAEwDQYJKoZIhvcN AQEFBQADgYEACzoHUF8UV2Z6541Q2wKEA0UFUzmUjf/E1XwBO+1P15ZZ64uw34B4 1RwMPtAo9RY/PmICTWtNxWGxkzwb2JtDWtnxVER/lF8k2XcXPE76fxTHJF/BKk9J QU8OTD1dd9gHCBviQB9TqntRZ5X7axjtuWjb2umY+owBYzAHZkp1HKI= -----END CERTIFICATE----- node-socks-proxy-agent-7.0.0/test/test.js000066400000000000000000000200531424542150600203350ustar00rootroot00000000000000/* global describe, before, after, it */ const socks = require('socksv5') const assert = require('assert') const https = require('https') const http = require('http') const url = require('url') const path = require('path') const fs = require('fs') const dns2 = require('dns2') const CacheableLookup = require('cacheable-lookup') const getRawBody = require('raw-body') const { SocksProxyAgent } = require('..') describe('SocksProxyAgent', function () { let httpServer let httpPort let httpsServer let httpsPort let socksServer let socksPort before(function (done) { // setup SOCKS proxy server socksServer = socks.createServer(function (info, accept, deny) { accept() }) socksServer.listen(0, '127.0.0.1', function () { socksPort = socksServer.address().port done() }) socksServer.useAuth(socks.auth.None()) }) before(function (done) { // setup target HTTP server httpServer = http.createServer() httpServer.listen(function () { httpPort = httpServer.address().port done() }) }) before(function (done) { // setup target SSL HTTPS server const options = { key: fs.readFileSync(path.resolve(__dirname, 'ssl-cert-snakeoil.key')), cert: fs.readFileSync(path.resolve(__dirname, 'ssl-cert-snakeoil.pem')) } httpsServer = https.createServer(options) httpsServer.listen(function () { httpsPort = httpsServer.address().port done() }) }) after(function (done) { socksServer.once('close', function () { done() }) socksServer.close() }) after(function (done) { httpServer.once('close', function () { done() }) httpServer.close() }) after(function (done) { httpsServer.once('close', function () { done() }) httpsServer.close() }) describe('constructor', function () { it('should throw an Error if no "proxy" argument is given', function () { assert.throws(() => new SocksProxyAgent()) }) it('should accept a "string" proxy argument', function () { const agent = new SocksProxyAgent(`socks://127.0.0.1:${socksPort}`) assert.equal('127.0.0.1', agent.proxy.host) assert.equal(socksPort, agent.proxy.port) }) it('should accept a `new URL()` result object argument', function () { const opts = new URL(`socks://127.0.0.1:${socksPort}`) const agent = new SocksProxyAgent(opts) assert.equal('127.0.0.1', agent.proxy.host) assert.equal(socksPort, agent.proxy.port) }) it('setup timeout', function (done) { httpServer.once('request', function (req, res) { assert.equal('/timeout', req.url) res.statusCode = 200 setTimeout(() => res.end('Written after 1000'), 500) }) const agent = new SocksProxyAgent(`socks://127.0.0.1:${socksPort}`, { timeout: 50 }) const opts = { protocol: 'http:', host: `127.0.0.1:${httpPort}`, port: httpPort, hostname: '127.0.0.1', path: '/timeout', agent, headers: { foo: 'bar' } } const req = http.get(opts, function () {}) req.once('error', err => { assert.equal(err.message, 'socket hang up') done() }) }) }) describe('"http" module', function () { it('should work against an HTTP endpoint', function (done) { httpServer.once('request', function (req, res) { assert.equal('/foo', req.url) res.statusCode = 404 res.end(JSON.stringify(req.headers)) }) const agent = new SocksProxyAgent(`socks://127.0.0.1:${socksPort}`) const opts = { protocol: 'http:', host: `127.0.0.1:${httpPort}`, port: httpPort, hostname: '127.0.0.1', path: '/foo', agent, headers: { foo: 'bar' } } const req = http.get(opts, function (res) { assert.equal(404, res.statusCode) getRawBody(res, 'utf8', function (err, buf) { if (err) return done(err) const data = JSON.parse(buf) assert.equal('bar', data.foo) done() }) }) req.once('error', done) }) }) describe('"https" module', function () { it('should work against an HTTPS endpoint', function (done) { httpsServer.once('request', function (req, res) { assert.equal('/foo', req.url) res.statusCode = 404 res.end(JSON.stringify(req.headers)) }) const agent = new SocksProxyAgent(`socks://127.0.0.1:${socksPort}`) const opts = { protocol: 'https:', host: `127.0.0.1:${httpsPort}`, port: httpsPort, hostname: '127.0.0.1', path: '/foo', agent, rejectUnauthorized: false, headers: { foo: 'bar' } } const req = https.get(opts, function (res) { assert.equal(404, res.statusCode) getRawBody(res, 'utf8', function (err, buf) { if (err) return done(err) const data = JSON.parse(buf) assert.equal('bar', data.foo) done() }) }) req.once('error', done) }) }) describe('Custom lookup option', function () { let dnsServer let dnsQueries before((done) => { dnsQueries = [] // A custom DNS server that always replies with 127.0.0.1: dnsServer = dns2.createServer({ udp: true, handle: (request, send) => { const response = dns2.Packet.createResponseFromRequest(request) const [ question ] = request.questions const { name } = question dnsQueries.push({ type: question.type, name: question.name }) response.answers.push({ name, type: dns2.Packet.TYPE.A, class: dns2.Packet.CLASS.IN, ttl: 300, address: '127.0.0.1' }) send(response) } }) dnsServer.listen({ udp: 5333 }) dnsServer.on('listening', () => done()) }) after(() => { dnsServer.close() }) it("should use a requests's custom lookup function with socks5", function(done) { httpServer.once('request', function(req, res) { assert.equal('/foo', req.url) res.statusCode = 404 res.end() }) let agent = new SocksProxyAgent(`socks5://127.0.0.1:${socksPort}`) let opts = url.parse(`http://non-existent-domain.test:${httpPort}/foo`) opts.agent = agent opts.lookup = (hostname, opts, callback) => { if (hostname === 'non-existent-domain.test') callback(null, '127.0.0.1') else callback(new Error("Bad domain")) } let req = http.get(opts, function(res) { assert.equal(404, res.statusCode) getRawBody(res, 'utf8', function(err, buf) { if (err) return done(err) done() }) }) req.once('error', done) }) it("should support caching DNS requests", function(done) { httpServer.on('request', function(req, res) { res.statusCode = 200 res.end() }) let agent = new SocksProxyAgent(`socks5://127.0.0.1:${socksPort}`) let opts = url.parse(`http://test-domain.test:${httpPort}/foo`) opts.agent = agent const cacheableLookup = new CacheableLookup() cacheableLookup.servers = ['127.0.0.1:5333'] opts.lookup = cacheableLookup.lookup // No DNS queries made initially assert.deepEqual(dnsQueries, []) http.get(opts, function(res) { assert.equal(200, res.statusCode) // Initial DNS query for first request assert.deepEqual(dnsQueries, [ { name: 'test-domain.test', type: dns2.Packet.TYPE.A }, { name: 'test-domain.test', type: dns2.Packet.TYPE.AAAA } ]) http.get(opts, function(res) { assert.equal(200, res.statusCode) // Still the same. No new DNS queries, so the response was cached assert.deepEqual(dnsQueries, [ { name: 'test-domain.test', type: dns2.Packet.TYPE.A }, { name: 'test-domain.test', type: dns2.Packet.TYPE.AAAA } ]) done() }).once('error', done) }).once('error', done) }) }) }) node-socks-proxy-agent-7.0.0/tsconfig.json000066400000000000000000000005421424542150600205510ustar00rootroot00000000000000{ "compilerOptions": { "strict": true, "module": "CommonJS", "target": "es2015", "esModuleInterop": true, "lib": ["esnext"], "outDir": "dist", "sourceMap": true, "declaration": true, "typeRoots": [ "./@types", "./node_modules/@types" ] }, "include": ["src/**/*"], "exclude": ["node_modules"] }