New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@applitools/eg-socks5-proxy-server

Package Overview
Dependencies
Maintainers
30
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@applitools/eg-socks5-proxy-server - npm Package Compare versions

Comparing version

to
0.2.0

src/authenticate.js

10

package.json
{
"name": "@applitools/eg-socks5-proxy-server",
"version": "0.1.7",
"version": "0.2.0",
"description": "",

@@ -17,3 +17,3 @@ "main": "src/index.js",

"test": "npm run eslint && npm run test:mocha-parallel",
"test:mocha": "mocha --no-timeouts --trace-warnings --exit 'test/unit/*.test.js' 'test/it/*.test.js' 'test/e2e/*.test.js'",
"test:mocha": "mocha --no-timeouts --trace-warnings --exit 'test/it/*.test.js'",
"eslint": "eslint '**/*.js'",

@@ -44,5 +44,7 @@ "build": "#"

"eslint-plugin-prettier": "^4.0.0",
"mocha": "^9.1.3",
"prettier": "^2.5.0"
"mocha": "^10.0.0",
"node-fetch": "^2.6.7",
"prettier": "^2.5.0",
"socks-proxy-agent": "^7.0.0"
}
}

397

src/index.js

@@ -11,3 +11,6 @@ const {

const {createRequestExecuter} = require('./create-request-executer')
const {handshake} = require('./handshake')
const {authenticate} = require('./authenticate')
const {executeRequest} = require('./execute-request')
const {executeRequestThroughRemoteProxy} = require('./execute-request-through-remote-proxy')

@@ -36,3 +39,2 @@ const binary = require('binary')

ORIGIN_SOCKET_ERROR: 'orgin-socket-error',

@@ -70,64 +72,14 @@ REMOTE_SOCKET_ERROR: 'remote-socket-error',

/**
* +----+------+----------+------+----------+
* |VER | ULEN | UNAME | PLEN | PASSWD |
* +----+------+----------+------+----------+
* | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
* +----+------+----------+------+----------+
*
*
* @param {Buffer} buffer - a buffer
* @returns {undefined}
**/
function authenticate(buffer) {
let authDomain = domain.create()
binary
.stream(buffer)
.word8('ver')
.word8('ulen')
.buffer('uname', 'ulen')
.word8('plen')
.buffer('passwd', 'plen')
.tap((args) => {
// capture the raw buffer
args.requestBuffer = buffer
// verify version is appropriate
if (args.ver !== RFC_1929_VERSION) {
return end(RFC_1929_REPLIES.GENERAL_FAILURE, args)
}
authDomain.on('error', (err) => {
// emit failed authentication event
self.server.emit(EVENTS.AUTHENTICATION_ERROR, args.uname.toString(), err)
// respond with auth failure
return end(RFC_1929_REPLIES.GENERAL_FAILURE, args)
})
// perform authentication
self.options.authenticate(
args.uname.toString(),
args.passwd.toString(),
socket,
authDomain.intercept(() => {
// emit successful authentication event
self.server.emit(EVENTS.AUTHENTICATION, args.uname.toString())
// respond with success...
let responseBuffer = Buffer.allocUnsafe(2)
responseBuffer[0] = RFC_1929_VERSION
responseBuffer[1] = RFC_1929_REPLIES.SUCCEEDED
// respond then listen for cmd and dst info
socket.write(responseBuffer, () => {
// now listen for more details
socket.once('data', connect)
})
}),
)
})
function _authenticate(buffer) {
authenticate({
socket,
buffer,
options: self.options,
connect,
end,
onAuthenticated: (args) => self.server.emit(EVENTS.AUTHENTICATION, args.uname.toString()),
onFailed: (args, err) =>
self.server.emit(EVENTS.AUTHENTICATION_ERROR, args.uname.toString(), err),
})
}
/**

@@ -212,35 +164,20 @@ * +----+-----+-------+------+----------+----------+

.tap((args) => {
if (args.cmd === RFC_1928_COMMANDS.CONNECT) {
let connectionFilter = self.options.connectionFilter,
connectionFilterDomain = domain.create()
if (args.cmd !== RFC_1928_COMMANDS.CONNECT) {
// bind and udp associate commands
return end(RFC_1928_REPLIES.SUCCEEDED, args)
}
// if no connection filter is provided, stub one
if (!connectionFilter || typeof connectionFilter !== 'function') {
connectionFilter = (destination, origin, callback) => setImmediate(callback)
}
let connectionFilter = self.options.connectionFilter,
connectionFilterDomain = domain.create()
// capture connection filter errors
connectionFilterDomain.on('error', (err) => {
// emit failed destination connection event
self.server.emit(
EVENTS.CONNECTION_FILTER,
// destination
{
address: args.dst.addr,
port: args.dst.port,
},
// origin
{
address: socket.remoteAddress,
port: socket.remotePort,
},
err,
)
// if no connection filter is provided, stub one
if (!connectionFilter || typeof connectionFilter !== 'function') {
connectionFilter = (destination, origin, callback) => setImmediate(callback)
}
// respond with failure
return end(RFC_1929_REPLIES.CONNECTION_NOT_ALLOWED, args)
})
// perform connection
return connectionFilter(
// capture connection filter errors
connectionFilterDomain.on('error', (err) => {
// emit failed destination connection event
self.server.emit(
EVENTS.CONNECTION_FILTER,
// destination

@@ -256,25 +193,116 @@ {

},
connectionFilterDomain.intercept(() => {
const destinationInfo = {
address: args.dst.addr,
port: args.dst.port,
err,
)
// respond with failure
return end(RFC_1929_REPLIES.CONNECTION_NOT_ALLOWED, args)
})
// perform connection
return connectionFilter(
// destination
{
address: args.dst.addr,
port: args.dst.port,
},
// origin
{
address: socket.remoteAddress,
port: socket.remotePort,
},
connectionFilterDomain.intercept(() => {
const destinationInfo = {
address: args.dst.addr,
port: args.dst.port,
}
const originInfo = {
address: socket.remoteAddress,
port: socket.remotePort,
}
let createExecuterAndRegisterToEvents
const proxyServer = self.options.proxyServer
? {...self.options.proxyServer}
: undefined
self.server.emit(EVENTS.ACCEPT_NEW_REQUEST, {
originInfo,
destinationInfo,
proxyServer,
})
createExecuterAndRegisterToEvents = () => {
let connectionTimeout = setTimeout(
() =>
self.server.emit(EVENTS.REMOTE_CONNECTION_TIMEOUT_ERROR, {
originInfo,
destinationInfo,
proxyServer,
}),
120000,
)
const clearConnectionTimeout = () => {
connectionTimeout && clearTimeout(connectionTimeout)
connectionTimeout = null
}
const originInfo = {
address: socket.remoteAddress,
port: socket.remotePort,
const onConnect = (destinationSocket) => {
connectionFilterDomain.exit()
clearConnectionTimeout()
// close destination socket when after original socket was closed
socket.on('close', () => {
destinationSocket.destroy()
self.destinationSockets.splice(self.destinationSockets.indexOf(socket), 1)
})
const event = proxyServer
? EVENTS.CONNECTED_TO_REMOTE_PROXY
: EVENTS.CONNECTED_TO_REMOTE_ADDRESS
self.server.emit(event, {destinationInfo, originInfo, proxyServer})
}
const proxyServer = self.options.proxyServer ? {...self.options.proxyServer} : undefined
const onError = (err) => {
// exit the connection filter domain
connectionFilterDomain.exit()
let createExecuterAndRegisterToEvents
self.server.emit(EVENTS.REMOTE_SOCKET_ERROR, {
err,
destination,
args,
originInfo,
destinationInfo,
proxyServer,
})
}
if (proxyServer){
let destination
if (!proxyServer) {
destination = executeRequest({
originalSocket: socket,
args,
end,
onConnect,
onError,
})
} else {
proxyServer.onHandShakeCompleted = () => {
self.server.emit(EVENTS.REMOTE_PROXY_HANDSHAKE_COMPLETED, {originInfo, destinationInfo, proxyServer})
self.server.emit(EVENTS.REMOTE_PROXY_HANDSHAKE_COMPLETED, {
originInfo,
destinationInfo,
proxyServer,
})
}
let retry = 0
proxyServer.onHandshakeTimeout = () => {
self.server.emit(EVENTS.REMOTE_PROXY_HANDSHAKE_TIMEOUT, {originInfo, destinationInfo, proxyServer})
self.server.emit(EVENTS.REMOTE_PROXY_HANDSHAKE_TIMEOUT, {
originInfo,
destinationInfo,
proxyServer,
})
retry++

@@ -284,27 +312,4 @@ if (retry <= 3) createExecuterAndRegisterToEvents()

}
}
self.server.emit(EVENTS.ACCEPT_NEW_REQUEST, {
originInfo,
destinationInfo,
proxyServer,
})
createExecuterAndRegisterToEvents = () => {
let connectionTimeout = setTimeout(
() =>
self.server.emit(EVENTS.REMOTE_CONNECTION_TIMEOUT_ERROR, {
originInfo,
destinationInfo,
proxyServer,
}),
120000,
)
const clearConnectionTimeout = () => {
connectionTimeout && clearTimeout(connectionTimeout)
connectionTimeout = null
}
let destination = createRequestExecuter({
destination = executeRequestThroughRemoteProxy({
originalSocket: socket,

@@ -314,60 +319,14 @@ clientHandshakeBuffer,

args,
end,
onConnect,
onError,
})
self.destinationSockets.push(socket)
destination.on('connect', () => {
connectionFilterDomain.exit()
clearConnectionTimeout()
// close destination socket when after original socket was closed
socket.on('close', () => {
destination.destroy()
self.destinationSockets.splice(self.destinationSockets.indexOf(socket), 1)
})
const event = proxyServer
? EVENTS.CONNECTED_TO_REMOTE_PROXY
: EVENTS.CONNECTED_TO_REMOTE_ADDRESS
self.server.emit(event, {destinationInfo, originInfo, proxyServer})
})
destination.on('error', (err) => {
// exit the connection filter domain
connectionFilterDomain.exit()
clearConnectionTimeout()
// notify of connection error
err.addr = args.dst.addr
err.atyp = args.atyp
err.port = args.dst.port
self.server.emit(EVENTS.REMOTE_SOCKET_ERROR, {
err,
destination,
args,
originInfo,
destinationInfo,
proxyServer,
})
if (err.code && err.code === 'EADDRNOTAVAIL') {
return end(RFC_1928_REPLIES.HOST_UNREACHABLE, args)
}
if (err.code && err.code === 'ECONNREFUSED') {
return end(RFC_1928_REPLIES.CONNECTION_REFUSED, args)
}
return end(RFC_1928_REPLIES.NETWORK_UNREACHABLE, args)
})
}
createExecuterAndRegisterToEvents()
}),
)
} else {
// bind and udp associate commands
return end(RFC_1928_REPLIES.SUCCEEDED, args)
}
self.destinationSockets.push(socket)
}
createExecuterAndRegisterToEvents()
}),
)
})

@@ -418,58 +377,22 @@ }

**/
function handshake(buffer) {
function _handshake(buffer) {
clientHandshakeBuffer = buffer
binary
.stream(buffer)
.word8('ver')
.word8('nmethods')
.buffer('methods', 'nmethods')
.tap((args) => {
// verify version is appropriate
if (args.ver !== RFC_1928_VERSION) {
return end(RFC_1928_REPLIES.GENERAL_FAILURE, args)
}
// convert methods buffer to an array
let acceptedMethods = [].slice.call(args.methods).reduce((methods, method) => {
methods[method] = true
return methods
}, {}),
basicAuth = typeof self.options.authenticate === 'function',
next = connect,
noAuth =
!basicAuth && typeof acceptedMethods[0] !== 'undefined' && acceptedMethods[0],
responseBuffer = Buffer.allocUnsafe(2)
const onHandshakeCompleted = (buffer) => {
self.server.emit(EVENTS.HANDSHAKE, socket)
}
// form response Buffer
responseBuffer[0] = RFC_1928_VERSION
responseBuffer[1] = RFC_1928_METHODS.NO_AUTHENTICATION_REQUIRED
// check for basic auth configuration
if (basicAuth) {
responseBuffer[1] = RFC_1928_METHODS.BASIC_AUTHENTICATION
next = authenticate
// if NO AUTHENTICATION REQUIRED and
} else if (!basicAuth && noAuth) {
responseBuffer[1] = RFC_1928_METHODS.NO_AUTHENTICATION_REQUIRED
next = connect
// basic auth callback not provided and no auth is not supported
} else {
return end(RFC_1928_METHODS.NO_ACCEPTABLE_METHODS, args)
}
// respond then listen for cmd and dst info
socket.write(responseBuffer, () => {
// emit handshake event
self.server.emit(EVENTS.HANDSHAKE, socket)
// now listen for more details
socket.once('data', next)
})
})
handshake({
socket,
buffer,
options: self.options,
connect,
authenticate: _authenticate,
onHandshakeCompleted,
end,
})
}
// capture the client handshake
socket.once('data', handshake)
socket.once('data', _handshake)

@@ -489,3 +412,3 @@ // capture socket closure

const createSocks5ProxyServer = ({options} = {}) => {
const createSocks5ProxyServer = (options) => {
let socksServer = new SocksServer(options)

@@ -492,0 +415,0 @@ return socksServer