socks-proxy-agent
Advanced tools
Comparing version 7.0.0 to 8.0.0
/// <reference types="node" /> | ||
/// <reference types="node" /> | ||
/// <reference types="node" /> | ||
import { SocksProxy } from 'socks'; | ||
import { Agent, ClientRequest, RequestOptions } from 'agent-base'; | ||
import { AgentOptions } from 'agent-base'; | ||
import { Url } from 'url'; | ||
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; | ||
} | ||
export interface SocksProxyAgentOptions extends AgentOptions, BaseSocksProxyAgentOptions, Partial<Omit<Url & SocksProxy, keyof BaseSocksProxyAgentOptions>> { | ||
} | ||
import { Agent, AgentConnectOpts } from 'agent-base'; | ||
import * as net from 'net'; | ||
import * as http from 'http'; | ||
export type SocksProxyAgentOptions = Omit<SocksProxy, 'ipaddress' | 'host' | 'port' | 'type' | 'userId' | 'password'> & http.AgentOptions; | ||
export declare class SocksProxyAgent extends Agent { | ||
private readonly shouldLookup; | ||
private readonly proxy; | ||
private readonly tlsConnectionOptions; | ||
static protocols: readonly ["socks", "socks4", "socks4a", "socks5", "socks5h"]; | ||
readonly shouldLookup: boolean; | ||
readonly proxy: SocksProxy; | ||
timeout: number | null; | ||
constructor(input: string | SocksProxyAgentOptions, options?: SocksProxyAgentOptionsExtra); | ||
constructor(uri: string | URL, opts?: SocksProxyAgentOptions); | ||
/** | ||
* Initiates a SOCKS connection to the specified SOCKS proxy server, | ||
* which in turn connects to the specified remote host and port. | ||
* | ||
* @api protected | ||
*/ | ||
callback(req: ClientRequest, opts: RequestOptions): Promise<net.Socket>; | ||
connect(req: http.ClientRequest, opts: AgentConnectOpts): Promise<net.Socket>; | ||
} | ||
export {}; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
@@ -19,76 +33,53 @@ var __importDefault = (this && this.__importDefault) || function (mod) { | ||
const debug_1 = __importDefault(require("debug")); | ||
const dns_1 = __importDefault(require("dns")); | ||
const tls_1 = __importDefault(require("tls")); | ||
const dns = __importStar(require("dns")); | ||
const net = __importStar(require("net")); | ||
const tls = __importStar(require("tls")); | ||
const debug = (0, debug_1.default)('socks-proxy-agent'); | ||
function parseSocksProxy(opts) { | ||
var _a; | ||
let port = 0; | ||
function parseSocksURL(url) { | ||
let lookup = false; | ||
let 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); | ||
} | ||
const host = url.hostname; | ||
// 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; | ||
} | ||
const port = parseInt(url.port, 10) || 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)}`); | ||
} | ||
switch (url.protocol.replace(':', '')) { | ||
case 'socks4': | ||
lookup = true; | ||
type = 4; | ||
break; | ||
// pass through | ||
case 'socks4a': | ||
type = 4; | ||
break; | ||
case 'socks5': | ||
lookup = true; | ||
type = 5; | ||
break; | ||
// pass through | ||
case 'socks': // no version specified, default to 5h | ||
type = 5; | ||
break; | ||
case 'socks5h': | ||
type = 5; | ||
break; | ||
default: | ||
throw new TypeError(`A "socks" protocol must be specified! Got: ${String(url.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 = { | ||
host, | ||
port, | ||
type | ||
type, | ||
}; | ||
let userId = (_a = opts.userId) !== null && _a !== void 0 ? _a : opts.username; | ||
let password = opts.password; | ||
if (opts.auth != null) { | ||
const auth = opts.auth.split(':'); | ||
userId = auth[0]; | ||
password = auth[1]; | ||
} | ||
if (userId != null) { | ||
if (url.username) { | ||
Object.defineProperty(proxy, 'userId', { | ||
value: userId, | ||
enumerable: false | ||
value: decodeURIComponent(url.username), | ||
enumerable: false, | ||
}); | ||
} | ||
if (password != null) { | ||
if (url.password != null) { | ||
Object.defineProperty(proxy, 'password', { | ||
value: password, | ||
enumerable: false | ||
value: decodeURIComponent(url.password), | ||
enumerable: false, | ||
}); | ||
@@ -98,25 +89,10 @@ } | ||
} | ||
const normalizeProxyOptions = (input) => { | ||
let proxyOptions; | ||
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; | ||
}; | ||
class SocksProxyAgent extends agent_base_1.Agent { | ||
constructor(input, options) { | ||
var _a; | ||
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 = (_a = options === null || options === void 0 ? void 0 : options.timeout) !== null && _a !== void 0 ? _a : null; | ||
constructor(uri, opts) { | ||
super(opts); | ||
const url = typeof uri === 'string' ? new URL(uri) : uri; | ||
const { proxy, lookup } = parseSocksURL(url); | ||
this.shouldLookup = lookup; | ||
this.proxy = proxy; | ||
this.timeout = opts?.timeout ?? null; | ||
} | ||
@@ -126,64 +102,72 @@ /** | ||
* which in turn connects to the specified remote host and port. | ||
* | ||
* @api protected | ||
*/ | ||
callback(req, opts) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
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 = yield new Promise((resolve, reject) => { | ||
// Use the request's custom lookup, if one was configured: | ||
const lookupFn = lookupCallback !== null && lookupCallback !== void 0 ? lookupCallback : dns_1.default.lookup; | ||
lookupFn(host, {}, (err, res) => { | ||
if (err) { | ||
reject(err); | ||
} | ||
else { | ||
resolve(res); | ||
} | ||
}); | ||
async connect(req, opts) { | ||
const { shouldLookup, proxy, timeout } = this; | ||
if (!opts.host) { | ||
throw new Error('No `host` defined!'); | ||
} | ||
let { host } = opts; | ||
const { port, lookup: lookupFn = dns.lookup } = opts; | ||
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: | ||
lookupFn(host, {}, (err, res) => { | ||
if (err) { | ||
reject(err); | ||
} | ||
else { | ||
resolve(res); | ||
} | ||
}); | ||
} | ||
const socksOpts = { | ||
proxy, | ||
destination: { host, port }, | ||
command: 'connect', | ||
timeout: timeout !== null && timeout !== void 0 ? timeout : undefined | ||
}; | ||
const cleanup = (tlsSocket) => { | ||
req.destroy(); | ||
socket.destroy(); | ||
if (tlsSocket) | ||
tlsSocket.destroy(); | ||
}; | ||
debug('Creating socks proxy connection: %o', socksOpts); | ||
const { socket } = yield socks_1.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 = (_a = opts.servername) !== null && _a !== void 0 ? _a : opts.host; | ||
const tlsSocket = tls_1.default.connect(Object.assign(Object.assign(Object.assign({}, 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; | ||
}); | ||
}); | ||
} | ||
const socksOpts = { | ||
proxy, | ||
destination: { | ||
host, | ||
port: typeof port === 'number' ? port : parseInt(port, 10), | ||
}, | ||
command: 'connect', | ||
timeout: timeout ?? undefined, | ||
}; | ||
const cleanup = (tlsSocket) => { | ||
req.destroy(); | ||
socket.destroy(); | ||
if (tlsSocket) | ||
tlsSocket.destroy(); | ||
}; | ||
debug('Creating socks proxy connection: %o', socksOpts); | ||
const { socket } = await socks_1.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', 'path', 'port'), | ||
socket, | ||
servername: net.isIP(servername) ? undefined : servername, | ||
}); | ||
tlsSocket.once('error', (error) => { | ||
debug('Socket TLS error', error.message); | ||
cleanup(tlsSocket); | ||
}); | ||
return tlsSocket; | ||
} | ||
return socket; | ||
} | ||
} | ||
SocksProxyAgent.protocols = [ | ||
'socks', | ||
'socks4', | ||
'socks4a', | ||
'socks5', | ||
'socks5h', | ||
]; | ||
exports.SocksProxyAgent = SocksProxyAgent; | ||
@@ -190,0 +174,0 @@ function omit(obj, ...keys) { |
105
package.json
{ | ||
"name": "socks-proxy-agent", | ||
"version": "8.0.0", | ||
"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", | ||
"main": "./dist/index.js", | ||
"types": "./dist/index.d.ts", | ||
"files": [ | ||
"dist" | ||
], | ||
"author": { | ||
@@ -92,7 +95,5 @@ "email": "nathan@tootallnate.net", | ||
"type": "git", | ||
"url": "git://github.com/TooTallNate/node-socks-proxy-agent.git" | ||
"url": "https://github.com/TooTallNate/proxy-agents.git", | ||
"directory": "packages/socks-proxy-agent" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/TooTallNate/node-socks-proxy-agent/issues" | ||
}, | ||
"keywords": [ | ||
@@ -110,74 +111,34 @@ "agent", | ||
"dependencies": { | ||
"agent-base": "^6.0.2", | ||
"debug": "^4.3.3", | ||
"socks": "^2.6.2" | ||
"agent-base": "^7.0.0", | ||
"debug": "^4.3.4", | ||
"socks": "^2.7.1" | ||
}, | ||
"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", | ||
"@types/async-retry": "^1.4.5", | ||
"@types/debug": "^4.1.7", | ||
"@types/dns2": "^2.0.3", | ||
"@types/jest": "^29.5.1", | ||
"@types/node": "^14.18.43", | ||
"async-listen": "^2.1.0", | ||
"async-retry": "^1.3.3", | ||
"cacheable-lookup": "^6.1.0", | ||
"dns2": "^2.1.0", | ||
"jest": "^29.5.0", | ||
"socksv5": "github:TooTallNate/socksv5#fix/dstSock-close-event", | ||
"standard": "latest", | ||
"standard-markdown": "latest", | ||
"standard-version": "latest", | ||
"ts-standard": "latest", | ||
"typescript": "latest" | ||
"ts-jest": "^29.1.0", | ||
"typescript": "^5.0.4", | ||
"proxy": "2.0.0", | ||
"tsconfig": "0.0.0" | ||
}, | ||
"engines": { | ||
"node": ">= 10" | ||
"node": ">= 14" | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"license": "MIT", | ||
"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" | ||
} | ||
"test": "jest --env node --verbose --bail test/test.ts", | ||
"test-e2e": "jest --env node --verbose --bail test/e2e.test.ts", | ||
"lint": "eslint . --ext .ts", | ||
"pack": "node ../../scripts/pack.mjs" | ||
} | ||
} |
socks-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) | ||
@@ -13,17 +12,5 @@ This module provides an `http.Agent` implementation that connects to a | ||
Installation | ||
------------ | ||
Install with `npm`: | ||
``` bash | ||
npm install socks-proxy-agent | ||
``` | ||
Examples | ||
-------- | ||
#### TypeScript example | ||
```ts | ||
@@ -33,8 +20,5 @@ import https from 'https'; | ||
const info = { | ||
hostname: 'br41.nordvpn.com', | ||
userId: 'your-name@gmail.com', | ||
password: 'abcdef12345124' | ||
}; | ||
const agent = new SocksProxyAgent(info); | ||
const agent = new SocksProxyAgent( | ||
'socks://your-name%40gmail.com:abcdef12345124@br41.nordvpn.com' | ||
); | ||
@@ -47,74 +31,14 @@ https.get('https://ipinfo.io', { agent }, (res) => { | ||
#### `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'); | ||
```ts | ||
import WebSocket from 'ws'; | ||
import { SocksProxyAgent } from '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); | ||
const agent = new SocksProxyAgent( | ||
'socks://your-name%40gmail.com:abcdef12345124@br41.nordvpn.com' | ||
); | ||
// 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); | ||
var socket = new WebSocket('ws://echo.websocket.events', { agent }); | ||
// 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 () { | ||
@@ -121,0 +45,0 @@ console.log('"open" event!'); |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
23913
15
7
380
77
7
+ Addedagent-base@7.1.1(transitive)
- Removedagent-base@6.0.2(transitive)
Updatedagent-base@^7.0.0
Updateddebug@^4.3.4
Updatedsocks@^2.7.1