Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

js2ray

Package Overview
Dependencies
Maintainers
1
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

js2ray - npm Package Compare versions

Comparing version 2.2.7 to 2.3.0

23

core/localNetwork.js

@@ -26,6 +26,6 @@

const remoteProtocol = localProtocol(localsocket, localsocket.remoteAddress)
localsocket.setTimeout(60000);
localsocket.setTimeout(30000);
localsocket.on('data', remoteProtocol.message);
localsocket.on("close", remoteProtocol.close)
localsocket.on("error", onerror)
localsocket.on("error", remoteProtocol.close)
});

@@ -45,2 +45,3 @@ return {

} else if (data.type == "ws") {
const wss = new WebSocketServer({ noServer: true });
if (data.option.fake) {

@@ -53,4 +54,3 @@ var server = http.createServer(function (req, res) {

}
const wss = new WebSocketServer({ server, path: data.option.path });
wss.on('connection', function (ws) {
function connected(ws) {
ws.localMessage = function (buffer) {

@@ -64,3 +64,10 @@ ws.send(buffer)

ws.on("close", function () { remoteProtocol.close() })
ws.on("error", function () { remoteProtocol.close() })
ws.on('message', function (buffer) { remoteProtocol.message(buffer) });
}
server.on('upgrade', function (request, socket, head) {
if (typeof data.option.path == "string" ? request.url == data.option.path : data.option.path.includes(request.url)) {
wss.handleUpgrade(request, socket, head, connected);
} else
socket.destroy();
});

@@ -106,4 +113,4 @@ return {

const remoteProtocol = localProtocol(localsocket, localsocket.remoteAddress)
localsocket.setTimeout(60000);
localsocket.on("error", onerror)
localsocket.setTimeout(30000);
localsocket.on("error", remoteProtocol.close)
localsocket.on("close", remoteProtocol.close)

@@ -173,4 +180,4 @@ localsocket.on('data', function (buffer) {

const remoteProtocol = localProtocol(localsocket, localsocket.remoteAddress)
localsocket.setTimeout(60000);
localsocket.on("error", onerror)
localsocket.setTimeout(30000);
localsocket.on("error", remoteProtocol.close)
localsocket.on("close", remoteProtocol.close)

@@ -177,0 +184,0 @@ localsocket.on('data', function (buffer) {

@@ -20,11 +20,24 @@

log("tcp client connected to " + address + " port " + port, 2)
const remotesocket = new net.Socket();
remotesocket.setTimeout(60000);
remotesocket.on('error', error);
remotesocket.on('close', remoteClose);
var remotesocket = new net.Socket();
function close() {
if (remotesocket == null)
return
remotesocket.destroy()
remotesocket = null
}
remotesocket.setTimeout(30000);
remotesocket.on('error', close);
remotesocket.on('close', function () {
remoteClose()
remotesocket = null
});
remotesocket.on('data', remoteMessage);
remotesocket.connect(port, address, remoteConnect);
return {
message: remotesocket.write.bind(remotesocket),
close: remotesocket.destroy.bind(remotesocket)
message: function (buffer) {
if (remotesocket == null)
return
remotesocket.write(buffer)
},
close
}

@@ -35,21 +48,32 @@ }

log("ws client connected to " + address + " port " + port, 2)
const remotesocket = new WebSocket('ws://' + address + ':' + port + data.option.path, {
var remotesocket = new WebSocket('ws://' + address + ':' + port + data.option.path, {
headers: data.option.headers
});
remotesocket.on('error', error);
function close() {
if (remotesocket == null)
return
remotesocket.close()
remotesocket = null
}
// =====================
const timeout = setTimeout(close, 30000)
remotesocket.on('error', close);
remotesocket.on('close', function () {
remoteClose()
clearTimeout(timeout)
remotesocket = null
});
remotesocket.on('message', function (buffer) {
remoteMessage(buffer)
clearTimeout(timeout)
});
// =====================
remotesocket.on('open', remoteConnect);
return {
message: function (buffer) {
if (remotesocket == null)
return
remotesocket.send(buffer)
},
close: function () {
remotesocket.close()
}
close
}

@@ -66,6 +90,15 @@ }

log("http client connected to " + address + " port " + port, 2)
const remotesocket = new net.Socket();
remotesocket.setTimeout(60000);
remotesocket.on('error', error);
remotesocket.on('close', remoteClose);
var remotesocket = new net.Socket();
function close() {
if (remotesocket == null)
return
remotesocket.destroy()
remotesocket = null
}
remotesocket.setTimeout(30000);
remotesocket.on('error', close);
remotesocket.on('close', function () {
remoteClose()
remotesocket = null
});
remotesocket.on('data', function (buffer) {

@@ -87,3 +120,3 @@ var indhttp = buffer.indexOf('\r\n\r\n')

message: function (buffer) {
if (remotesocket.readyState == "closed")
if (remotesocket == null)
return

@@ -96,3 +129,3 @@ if (remotesocket.rh != true) {

},
close: remotesocket.destroy.bind(remotesocket)
close
}

@@ -99,0 +132,0 @@ }

@@ -5,3 +5,3 @@

const freedom = require('./protocols/freedom');
const bridge = require('./protocols/bridge');
// const bridge = require('./protocols/bridge');
const localNetwork = require('./core/localNetwork');

@@ -62,2 +62,3 @@ const remoteNetwork = require('./core/remoteNetwork');

}
return false;
}

@@ -64,0 +65,0 @@ if (data.api)

@@ -11,3 +11,3 @@ const fs = require("fs")

Restart=always
RestartSec=10
RestartSec=200ms
StandardOutput=syslog

@@ -14,0 +14,0 @@ StandardError=syslog

{
"name": "js2ray",
"version": "2.2.7",
"version": "2.3.0",
"description": "The v2ray vmess protocol, based on nodejs javascript which you can use on hosts and servers",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -6,5 +6,2 @@

function onerror(e) {
// log(e)
}
function freedom(address, port, cmd, onconnect, onmessage, onclose) {

@@ -14,9 +11,27 @@ if (cmd == 2) {

var dgramsocket = dgram.createSocket('udp4');
function close() {
if (dgramsocket == null)
return
dgramsocket.close()
dgramsocket = null
}
dgramsocket.on('error', close);
dgramsocket.on('message', onmessage)
// =====================
const timeout = setTimeout(close, 30000)
dgramsocket.on('close', function () {
onclose()
dgramsocket = null
clearTimeout(timeout)
});
dgramsocket.on('message', clearTimeout.bind(null, timeout));
// =====================
dgramsocket.connect(port, address, onconnect);
dgramsocket.on('close', onclose);
dgramsocket.on('error', onerror);
dgramsocket.on('message', onmessage)
return {
close: dgramsocket.close.bind(dgramsocket),
message: dgramsocket.send.bind(dgramsocket),
close,
message: function (buffer) {
if (dgramsocket == null)
return
dgramsocket.send(buffer)
},
}

@@ -26,10 +41,23 @@ } else {

var remotesocket = new net.Socket();
remotesocket.setTimeout(60000)
function close() {
if (remotesocket == null)
return
remotesocket.destroy()
remotesocket = null
}
remotesocket.on('close', function () {
onclose()
remotesocket = null
});
remotesocket.on('data', onmessage);
remotesocket.on('error', close)
remotesocket.setTimeout(30000)
remotesocket.connect(port, address, onconnect);
remotesocket.on('close', onclose);
remotesocket.on('error', onerror);
remotesocket.on('data', onmessage);
return {
close: remotesocket.destroy.bind(remotesocket),
message: remotesocket.write.bind(remotesocket),
close,
message: function (buffer) {
if (remotesocket == null)
return
remotesocket.write(buffer)
}
}

@@ -40,41 +68,2 @@ }

// // UDP socket with timeout
// const dns = require("dns");
// const dgram = require("dgram");
// const dnsPacket = require("dns-packet");
// const _resolveUDP = (packet, addr, port = 53, timeout) => {
// return new Promise((resolve, reject) => {
// const socket = dgram.createSocket("udp4");
// const id = setTimeout(() => {
// clearTimeout(id);
// socket.close();
// reject("timed out");
// return;
// }, parseInt(timeout));
// socket.on("message", message => {
// clearTimeout(id); // Clear the timeout if you are going to close the socket manually.
// socket.close();
// resolve(dnsPacket.decode(message));
// return;
// });
// socket.on("error", err => {
// clearTimeout(id); // Clear the timeout if you are going to close the socket manually.
// socket.close();
// reject(err);
// return;
// });
// socket.send(packet, 0, packet.length, parseInt(port), addr, err => {
// if (err) {
// clearTimeout(id); // Clear the timeout if you are going to close the socket manually.
// socket.close();
// reject(err);
// }
// });
// });
// };

@@ -119,7 +119,9 @@

ipCount: a.ipCount || 0,
ipCountDuration: a.ipCountDuration || 40,
ipCountDuration: a.ipCountDuration || 600,
email: a.email,
expire: a.expire,
deactive: a.deactive || 0,
ipList: a.ipList || {}
ipList: a.ipList || {},
ipWarning: a.ipWarning || {},
ipBlock: a.ipBlock || {},
}

@@ -126,0 +128,0 @@ users[tag][id] = user

@@ -47,6 +47,9 @@

socket.app = app
socket.app.close = socket.close
return {
message: EncodeRequestBody.bind(socket, randomuser),
close: onclose.bind(socket),
close: function () {
onclose(socket.app)
delete socket.app
}
}

@@ -56,5 +59,8 @@ }

function onclose() {
this.close()
const app = this.app
function onerror(app, error, ind) {
onclose(app);
log(error, ind)
}
function onclose(app) {
app._isConnecting = false;

@@ -77,2 +83,3 @@ app._isHeaderSent = false;

app._chunkLenDecMaskGenerator = null;
app.close()

@@ -84,20 +91,22 @@ }

const app = this.app
if (!app._isHeaderSent) {
app._isHeaderSent = true;
const header = EncodeRequestHeader(app, randomuser)
if (header) {
if (app) {
if (!app._isHeaderSent) {
app._isHeaderSent = true;
const header = EncodeRequestHeader(app, randomuser)
if (header) {
if (app.user.deactive)
return
app.user.bytesRead += buffer.length
const chunks = common.getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
this.message(Buffer.concat([header, ...chunks]))
}
} else {
if (app.user.deactive)
return
if (app.user.traffic != 0 && common.trafficlimit(app.user))
return onerror(app, `maximum traffic ${app.user.traffic / 1024 / 1024}MB (bytesRead:${app.user.bytesRead},bytesWrit:${app.user.bytesWrit}) used by user ${app.user.id.UUID.toString("hex")}`, 1);
app.user.bytesRead += buffer.length
const chunks = common.getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
this.message(Buffer.concat([header, ...chunks]))
this.message(Buffer.concat(chunks))
}
} else {
if (app.user.deactive)
return
if (app.user.traffic != 0 && common.trafficlimit(app.user))
return log(`maximum traffic ${app.user.traffic / 1024 / 1024}MB (bytesRead:${app.user.bytesRead},bytesWrit:${app.user.bytesWrit}) used by user ${app.user.id.UUID.toString("hex")}`, 1);
app.user.bytesRead += buffer.length
const chunks = common.getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
this.message(Buffer.concat(chunks))
}

@@ -113,3 +122,3 @@ }

if (random_user.traffic != 0 && common.trafficlimit(random_user)) {
return log(`maximum traffic ${random_user.traffic / 1024 / 1024}MB (bytesRead:${random_user.bytesRead},bytesWrit:${random_user.bytesWrit}) used by user ${random_user.id.UUID.toString("hex")}`, 1)
return onerror(app, `maximum traffic ${random_user.traffic / 1024 / 1024}MB (bytesRead:${random_user.bytesRead},bytesWrit:${random_user.bytesWrit}) used by user ${random_user.id.UUID.toString("hex")}`, 1)
}

@@ -148,2 +157,5 @@ // IV and Key for data chunks encryption/decryption

}
if (app._host.length > 255) {
return onerror(app, `domain name is too long`, 1)
}
// create encrypted command

@@ -179,7 +191,7 @@ let command = Buffer.from([

if (aeadHeader == undefined) {
return log(`AEAD read failed`, 1)
return onerror(app, `AEAD read failed`, 1)
}
return aeadHeader;
} else {
return log(`invalid user`, 1);
return onerror(app, `invalid user`, 1);
}

@@ -199,3 +211,3 @@ }

if (app._v !== header[0]) {
return log(`server response v doesn't match, expect ${app._v} but got ${header[0]}`, 1);
return onerror(app, `server response v doesn't match, expect ${app._v} but got ${header[0]}`, 1);
}

@@ -226,3 +238,3 @@ app._isHeaderRecv = true;

if (app._v !== header[0]) {
return log(`server response v doesn't match, expect ${app._v} but got ${header[0]}`, 1);
return onerror(app, `server response v doesn't match, expect ${app._v} but got ${header[0]}`, 1);
}

@@ -233,3 +245,3 @@ app._isHeaderRecv = true;

} catch (error) {
return log(`unable to authenticate server response data: ${error}`)
return onerror(app, `unable to authenticate server response data: ${error}`)
}

@@ -244,3 +256,3 @@ }

if (data === null) {
return log(`fail to decrypt data chunk`, 1);
return onerror(app, `fail to decrypt data chunk`, 1);
}

@@ -247,0 +259,0 @@ app.user.bytesWrit += data.length

@@ -13,10 +13,9 @@

function ntb(num, len = 2, byteOrder = 0) {
if (len < 1) {
throw Error('len must be greater than 0');
}
const buf = Buffer.alloc(len);
if (byteOrder === 0) {
buf.writeUIntBE(num, 0, len);
} else {
buf.writeUIntLE(num, 0, len);
if (len > 0 && num >= 0 && num <= Math.pow(256, len) - 1) {
if (byteOrder === 0) {
buf.writeUIntBE(num, 0, len);
} else {
buf.writeUIntLE(num, 0, len);
}
}

@@ -73,24 +72,27 @@ return buf;

const security = app._security;
const nonce = Buffer.concat([ntb(app._cipherNonce), app._dataEncIV.subarray(2, 12)]);
let ciphertext = null;
let tag = null;
if (security === consts.SECURITY_TYPE_AES_128_GCM) {
const cipher = crypto.createCipheriv('aes-128-gcm', app._dataEncKey, nonce);
ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
tag = cipher.getAuthTag();
app._cipherNonce += 1;
if (app._cipherNonce > 65535)
app._cipherNonce = 0
if (app._dataEncIV) {
let tag = null;
const nonce = Buffer.concat([ntb(app._cipherNonce), app._dataEncIV.subarray(2, 12)]);
let ciphertext = null;
if (security === consts.SECURITY_TYPE_AES_128_GCM) {
const cipher = crypto.createCipheriv('aes-128-gcm', app._dataEncKey, nonce);
ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
tag = cipher.getAuthTag();
app._cipherNonce += 1;
if (app._cipherNonce > 65535)
app._cipherNonce = 0
}
else if (security === consts.SECURITY_TYPE_CHACHA20_POLY1305) {
const cipher = crypto.createCipheriv('chacha20-poly1305', app._dataEncKeyForChaCha20, nonce, {
authTagLength: 16
})
ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
tag = cipher.getAuthTag();
app._cipherNonce += 1;
if (app._cipherNonce > 65535)
app._cipherNonce = 0
}
return Buffer.concat([ciphertext, tag]);
}
else if (security === consts.SECURITY_TYPE_CHACHA20_POLY1305) {
const cipher = crypto.createCipheriv('chacha20-poly1305', app._dataEncKeyForChaCha20, nonce, {
authTagLength: 16
})
ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
tag = cipher.getAuthTag();
app._cipherNonce += 1;
if (app._cipherNonce > 65535)
app._cipherNonce = 0
}
return Buffer.concat([ciphertext, tag]);
return Buffer.alloc(0)
}

@@ -157,6 +159,27 @@ function decrypt(ciphertext, app) {

}
function iplimit(ip, user) {
function iplimit(ip, user) {
var now = Math.round(new Date() / 1000)
if (!(ip in user.ipList)) {
if (user.ipCount && !(ip in user.ipList)) {
if (Object.keys(user.ipList).length >= user.ipCount) {
if (user.ipBlock[ip] && user.ipBlock[ip] + user.ipCountDuration > now) {
// ======================================= soft allow for 1 or 2 ip
if (ip in user.ipWarning) {
if (user.ipWarning[ip] + user.ipCountDuration / 20 < now) {
return false
}
} else if (Object.keys(user.ipWarning).length <= Math.max(1, Math.round(user.ipCount / 2.1))) {
user.ipWarning[ip] = now
} else {
if (!user.maxip) {
event.emit("ip", user.id.UUID)
user.maxip = true
}
}
return true
// ===================================================
} else {
delete user.ipBlock[ip]
user.maxip = false
}
//================================================ clear ips
for (const i in user.ipList) {

@@ -167,15 +190,65 @@ if (user.ipList[i] + user.ipCountDuration < now) {

}
if (Object.keys(user.ipList).length >= user.ipCount) {
if (!user.maxip) {
event.emit("ip", user.id.UUID)
user.maxip = true
if (user.ipList.length == 0)
user.maxip = false
for (const i in user.ipWarning) {
if (user.ipWarning[i] + user.ipCountDuration < now) {
delete user.ipWarning[i]
}
return true;
}
//===================================================
const keys = Object.keys(user.ipList)
if (keys.length >= user.ipCount) {
var wip = keys.reduce((key, v) => user.ipList[v] < user.ipList[key] ? v : key);
user.ipBlock[wip] = user.ipList[wip]
delete user.ipList[wip];
for (const i in user.ipBlock) {
if (user.ipBlock[i] + user.ipCountDuration < now) {
delete user.ipBlock[i]
}
}
}
}
}
if (user.maxip)
user.maxip = false
user.ipList[ip] = now
return false
}
// function update_ip(ip, user) {
// user.ipList[ip] = now
// }
// function iplimit(ip, user) {
// var now = Math.round(new Date() / 1000)
// if (!(ip in user.ipList)) {
// if (Object.keys(user.ipList).length >= user.ipCount) {
// // ================================================
// for (const i in user.ipBlock) {
// if (user.ipBlock[i] + user.ipCountDuration < now) {
// delete user.ipBlock[i]
// }
// }
// if (Object.keys(user.ipBlock).length >= Math.max(2, Math.round(user.ipCount / 2))) {
// if (!user.maxip) {
// event.emit("ip", user.id.UUID)
// user.maxip = true
// }
// return true
// }
// //================================================ clear ips
// for (const i in user.ipList) {
// if (user.ipList[i] + 30 < now) {
// delete user.ipList[i]
// }
// }
// //================================================
// if (Object.keys(user.ipList).length >= user.ipCount) {
// user.ipBlock[ip] = now
// return true
// }
// }
// }
// if (user.maxip)
// user.maxip = false
// user.ipList[ip] = now
// }
function iptoString(buff, offset, length) {

@@ -278,2 +351,3 @@ offset = ~~offset;

trafficlimit,
update_ip: iplimit,
iplimit

@@ -280,0 +354,0 @@ }

@@ -20,4 +20,4 @@

function Check(filter, sum) {
var now = Math.round(new Date() / 1000)
if (now - filter.lastSwap >= filter.Interval) {
var now = Math.round(new Date() / 1000)
if (now - filter.lastSwap >= filter.interval) {
if (filter.poolSwap) {

@@ -24,0 +24,0 @@ filter.poolA.clear()

@@ -32,3 +32,6 @@

message: DecodeRequestHeader.bind(socket, remoteProtocol, EncodeResponseBody.bind(socket), socket.localClose, checkuser),
close: onclose.bind(socket),
close: function () {
onclose(socket.app);
delete socket.app
},
}

@@ -41,185 +44,189 @@ }

const app = this.app
if (!app._isHeaderRecv) {
if (app._isConnecting) {
app._staging = Buffer.concat([app._staging, buffer]);
return;
}
if (app) {
if (!app._isHeaderRecv) {
if (app._isConnecting) {
app._staging = Buffer.concat([app._staging, buffer]);
return;
}
if (buffer.length < 16) {
return log(`fail to parse request header: ${buffer.toString("hex")}`, 1);
}
if (buffer.length < 16) {
return onerror(app, `fail to parse request header: ${buffer.toString("hex")}`, 1);
}
const reqCommand = Buffer.from(buffer.subarray(16));
var aeadUser = checkuser(buffer.subarray(0, 16), true)
if (aeadUser == undefined) {
var dataoffset = 16
const user = checkuser(buffer.subarray(0, 16).toString("hex"));
if (user == undefined)
return log(`cannot find ${buffer.subarray(0, 16).toString("hex")} in cache, maybe a wrong auth info`, 1);
var ts = user[1]
aeadUser = user[0]
var decipher = crypto.createDecipheriv('aes-128-cfb', aeadUser.id.cmdKey,
common.hash('md5', Buffer.concat([ts, ts, ts, ts])));
decipher.subarray = function (a, b) {
return this.update(reqCommand.subarray(a, b))
const reqCommand = Buffer.from(buffer.subarray(16));
var aeadUser = checkuser(buffer.subarray(0, 16), true)
if (aeadUser == undefined) {
var dataoffset = 16
const user = checkuser(buffer.subarray(0, 16).toString("hex"));
if (user == undefined)
return onerror(app, `cannot find ${buffer.subarray(0, 16).toString("hex")} in cache, maybe a wrong auth info`, 1);
var ts = user[1]
aeadUser = user[0]
var decipher = crypto.createDecipheriv('aes-128-cfb', aeadUser.id.cmdKey,
common.hash('md5', Buffer.concat([ts, ts, ts, ts])));
decipher.subarray = function (a, b) {
return this.update(reqCommand.subarray(a, b))
}
app.user = aeadUser
app._isAEADRequest = false
} else if (typeof aeadUser == "object") {
var decipher = validator.OpenVMessAEADHeader(aeadUser.id.cmdKey, buffer)
// 16 + 12 + 12 + 18
var dataoffset = 58
if (decipher == undefined) {
return onerror(app, `AEAD read failed`, 1)
}
app.user = aeadUser
app._isAEADRequest = true
} else {
return onerror(app, `invalid user`, 1);
}
app.user = aeadUser
app._isAEADRequest = false
} else if (typeof aeadUser == "object") {
var decipher = validator.OpenVMessAEADHeader(aeadUser.id.cmdKey, buffer)
// 16 + 12 + 12 + 18
var dataoffset = 58
if (decipher == undefined) {
return log(`AEAD read failed`, 1)
if (aeadUser.deactive)
return
if (aeadUser.ipCount != 0 && common.iplimit(app.ip, aeadUser))
return onerror(app, `maximum ip used by user ${aeadUser.id.UUID.toString("hex")}`, 1)
if (aeadUser.traffic != 0 && common.trafficlimit(aeadUser)) {
return onerror(app, `maximum traffic ${aeadUser.traffic / 1024 / 1024}MB (bytesRead:${aeadUser.bytesRead},bytesWrit:${aeadUser.bytesWrit}) used by user ${aeadUser.id.UUID.toString("hex")}`, 1)
}
app.user = aeadUser
app._isAEADRequest = true
} else {
return log(`invalid user`, 1);
}
if (aeadUser.deactive)
return
if (aeadUser.expire && aeadUser.expire < new Date().getTime()) {
return onerror(app, `expire user ${aeadUser.id.UUID.toString("hex")}`, 1)
}
if (aeadUser.ipCount != 0 && common.iplimit(app.ip, aeadUser))
return log(`maximum ip used by user ${aeadUser.id.UUID.toString("hex")}`, 1)
if (reqCommand.length < 41) {
return onerror(app, `request command is too short: ${reqCommand.length}bytes, command=${reqCommand.toString('hex')}`, 1);
}
if (aeadUser.traffic != 0 && common.trafficlimit(aeadUser)) {
return log(`maximum traffic ${aeadUser.traffic / 1024 / 1024}MB (bytesRead:${aeadUser.bytesRead},bytesWrit:${aeadUser.bytesWrit}) used by user ${aeadUser.id.UUID.toString("hex")}`, 1)
}
if (aeadUser.expire && aeadUser.expire < new Date().getTime()) {
return log(`expire user ${aeadUser.id.UUID.toString("hex")}`, 1)
}
const reqHeader = decipher.subarray(0, 41);
const ver = reqHeader[0];
if (reqCommand.length < 41) {
return log(`request command is too short: ${reqCommand.length}bytes, command=${reqCommand.toString('hex')}`, 1);
}
if (ver !== 0x01) {
return onerror(app, `invalid version number: ${ver}`, 1);
}
const reqHeader = decipher.subarray(0, 41);
const ver = reqHeader[0];
app._dataDecIV = reqHeader.subarray(1, 17);
app._dataDecKey = reqHeader.subarray(17, 33);
if (app._isAEADRequest) {
app._dataEncIV = common.hash('sha256', app._dataDecIV).subarray(0, 16);
app._dataEncKey = common.hash('sha256', app._dataDecKey).subarray(0, 16);
app.lengthEnKey = kdf.KDF16(app._dataEncKey, consts.KDFSaltConstAEADRespHeaderLenKey)
app.lengthEnIV = kdf.KDF(app._dataEncIV, consts.KDFSaltConstAEADRespHeaderLenIV).subarray(0, 12)
app.payloadEnKey = kdf.KDF16(app._dataEncKey, consts.KDFSaltConstAEADRespHeaderPayloadKey)
app.payloadEnIV = kdf.KDF(app._dataEncIV, consts.KDFSaltConstAEADRespHeaderPayloadIV).subarray(0, 12)
} else {
app._dataEncIV = common.hash('md5', app._dataDecIV);
app._dataEncKey = common.hash('md5', app._dataDecKey);
}
if (ver !== 0x01) {
return log(`invalid version number: ${ver}`, 1);
}
app._dataDecIV = reqHeader.subarray(1, 17);
app._dataDecKey = reqHeader.subarray(17, 33);
if (app._isAEADRequest) {
app._dataEncIV = common.hash('sha256', app._dataDecIV).subarray(0, 16);
app._dataEncKey = common.hash('sha256', app._dataDecKey).subarray(0, 16);
app.lengthEnKey = kdf.KDF16(app._dataEncKey, consts.KDFSaltConstAEADRespHeaderLenKey)
app.lengthEnIV = kdf.KDF(app._dataEncIV, consts.KDFSaltConstAEADRespHeaderLenIV).subarray(0, 12)
app.payloadEnKey = kdf.KDF16(app._dataEncKey, consts.KDFSaltConstAEADRespHeaderPayloadKey)
app.payloadEnIV = kdf.KDF(app._dataEncIV, consts.KDFSaltConstAEADRespHeaderPayloadIV).subarray(0, 12)
} else {
app._dataEncIV = common.hash('md5', app._dataDecIV);
app._dataEncKey = common.hash('md5', app._dataDecKey);
}
app._chunkLenDecMaskGenerator = common.shake128(app._dataDecIV);
app._chunkLenEncMaskGenerator = common.shake128(app._dataEncIV);
app._responseHeader = reqHeader[33];
app._option = reqHeader[34];
const paddingLen = reqHeader[35] >> 4;
// 2 'auto'
// 3 'aes-128-gcm'
// 4 'chacha20-poly1305'
// 5 'none'
// 6 'zero'
const securityType = reqHeader[35] & 0x0F;
if (!(aeadUser.security == 2 || aeadUser.security == undefined || securityType == 2) && securityType != aeadUser.security) {
return onerror(app, `not match securety type`, 1);
}
if (securityType == consts.SECURITY_TYPE_CHACHA20_POLY1305) {
app._dataEncKeyForChaCha20 = common.createChacha20Poly1305Key(app._dataEncKey);
app._dataDecKeyForChaCha20 = common.createChacha20Poly1305Key(app._dataDecKey);
}
//===========
let offset = 40;
var cmd = reqHeader[37];
if (![0x01, 0x02, 0x03].includes(cmd)) {
return onerror(app, `unsupported cmd: ${cmd}`, 1);
}
if (cmd == 0x03) {
var port = 0
var addr = "v1.mux.cool"
var addrType = ATYP_DOMAIN
}
else {
var port = reqHeader.readUInt16BE(38);
var addrType = reqHeader[40];
var addr = null;
if (addrType === ATYP_V4) {
if (reqCommand.length < 45) {
return onerror(app, `request command is too short ${reqCommand.length}bytes to get ipv4, command=${reqCommand.toString('hex')}`, 1);
}
app._chunkLenDecMaskGenerator = common.shake128(app._dataDecIV);
app._chunkLenEncMaskGenerator = common.shake128(app._dataEncIV);
addr = decipher.subarray(41, 45);
offset += 4;
} else if (addrType === ATYP_V6) {
if (reqCommand.length < 57) {
return onerror(app, `request command is too short: ${reqCommand.length}bytes to get ipv6, command=${reqCommand.toString('hex')}`, 1);
}
app._responseHeader = reqHeader[33];
app._option = reqHeader[34];
const paddingLen = reqHeader[35] >> 4;
// 2 'auto'
// 3 'aes-128-gcm'
// 4 'chacha20-poly1305'
// 5 'none'
// 6 'zero'
const securityType = reqHeader[35] & 0x0F;
if (!(aeadUser.security == 2 || aeadUser.security == undefined || securityType == 2) && securityType != aeadUser.security) {
return log(`not match securety type`, 1);
}
if (securityType == consts.SECURITY_TYPE_CHACHA20_POLY1305) {
app._dataEncKeyForChaCha20 = common.createChacha20Poly1305Key(app._dataEncKey);
app._dataDecKeyForChaCha20 = common.createChacha20Poly1305Key(app._dataDecKey);
}
//===========
let offset = 40;
var cmd = reqHeader[37];
if (![0x01, 0x02, 0x03].includes(cmd)) {
return log(`unsupported cmd: ${cmd}`, 1);
}
if (cmd == 0x03) {
var port = 0
var addr = "v1.mux.cool"
var addrType = ATYP_DOMAIN
}
else {
var port = reqHeader.readUInt16BE(38);
var addrType = reqHeader[40];
var addr = null;
if (addrType === ATYP_V4) {
if (reqCommand.length < 45) {
return log(`request command is too short ${reqCommand.length}bytes to get ipv4, command=${reqCommand.toString('hex')}`, 1);
}
addr = decipher.subarray(41, 57);
offset += 16;
} else if (addrType === ATYP_DOMAIN) {
if (reqCommand.length < 42) {
return onerror(app, `request command is too short: ${reqCommand.length}bytes to get host name, command=${reqCommand.toString('hex')}`, 1);
}
addr = decipher.subarray(41, 45);
offset += 4;
} else if (addrType === ATYP_V6) {
if (reqCommand.length < 57) {
return log(`request command is too short: ${reqCommand.length}bytes to get ipv6, command=${reqCommand.toString('hex')}`, 1);
}
const addrLen = decipher.subarray(41, 42)[0];
addr = decipher.subarray(41, 57);
offset += 16;
} else if (addrType === ATYP_DOMAIN) {
if (reqCommand.length < 42) {
return log(`request command is too short: ${reqCommand.length}bytes to get host name, command=${reqCommand.toString('hex')}`, 1);
}
if (reqCommand.length < 42 + addrLen) {
return onerror(app, `request command is too short: ${reqCommand.length}bytes, command=${reqCommand.toString('hex')}`, 1);
}
const addrLen = decipher.subarray(41, 42)[0];
if (reqCommand.length < 42 + addrLen) {
return log(`request command is too short: ${reqCommand.length}bytes, command=${reqCommand.toString('hex')}`, 1);
addr = decipher.subarray(42, 42 + addrLen);
offset += 1 + addrLen;
} else {
return onerror(app, `unknown address type: ${addrType}, command=${reqHeader.toString('hex')}`, 1);
}
}
addr = decipher.subarray(42, 42 + addrLen);
offset += 1 + addrLen;
} else {
return log(`unknown address type: ${addrType}, command=${reqHeader.toString('hex')}`, 1);
if (reqCommand.length < offset + paddingLen + 4) {
return onerror(app, `request command is too short: ${reqCommand.length}bytes to get padding and f, command=${reqCommand.toString('hex')}`, 1);
}
}
if (reqCommand.length < offset + paddingLen + 4) {
return log(`request command is too short: ${reqCommand.length}bytes to get padding and f, command=${reqCommand.toString('hex')}`, 1);
}
const padding = decipher.subarray(offset, offset + paddingLen);
offset += paddingLen;
const f = decipher.subarray(offset, offset + 4);
const padding = decipher.subarray(offset, offset + paddingLen);
offset += paddingLen;
const f = decipher.subarray(offset, offset + 4);
const plainReqHeader = Buffer.from([...reqHeader.subarray(0, 41), ...(addrType === ATYP_DOMAIN ? [addr.length] : []), ...addr, ...padding]);
const plainReqHeader = Buffer.from([...reqHeader.subarray(0, 41), ...(addrType === ATYP_DOMAIN ? [addr.length] : []), ...addr, ...padding]);
if (common.fnv1a(plainReqHeader).equals(f)) {
return log('fail to verify request command', 1);
if (common.fnv1a(plainReqHeader).equals(f)) {
return onerror(app, 'fail to verify request command', 1);
}
const data = buffer.subarray(dataoffset + plainReqHeader.length + 4);
app._security = securityType;
app._isConnecting = true;
app.remote = remoteProtocol(
addrType === ATYP_DOMAIN ? addr.toString() : common.iptoString(addr),
port,
cmd,
function () {
if (!app._adBuf)
return
app._adBuf.put(Buffer.concat([data, app._staging]), app);
app._isHeaderRecv = true;
app._isConnecting = false;
app._staging = null;
},
onRemoteMessage,
onRemoteClose
)
} else {
if (app.user.deactive)
return
if (common.update_ip(app.ip, app.user))
return onerror(app, `maximum ip used by user ${app.user.id.UUID.toString("hex")}`, 1)
if (app.user.traffic != 0 && common.trafficlimit(app.user))
return onerror(app, `maximum traffic ${app.user.traffic / 1024 / 1024}MB (bytesRead:${app.user.bytesRead},bytesWrit:${app.user.bytesWrit}) used by user ${app.user.id.UUID.toString("hex")}`, 1);
if (app.user.expire && app.user.expire < new Date().getTime()) {
return onerror(app, `expire user ${app.user.id.UUID.toString("hex")}`, 1)
}
app._adBuf.put(buffer, app);
}
const data = buffer.subarray(dataoffset + plainReqHeader.length + 4);
app._security = securityType;
app._isConnecting = true;
app.remote = remoteProtocol(
addrType === ATYP_DOMAIN ? addr.toString() : common.iptoString(addr),
port,
cmd,
function () {
if (!app._adBuf)
return
app._adBuf.put(Buffer.concat([data, app._staging]), app);
app._isHeaderRecv = true;
app._isConnecting = false;
app._staging = null;
},
onRemoteMessage,
onRemoteClose
)
} else {
if (app.user.deactive)
return
if (app.user.traffic != 0 && common.trafficlimit(app.user))
return log(`maximum traffic ${app.user.traffic / 1024 / 1024}MB (bytesRead:${app.user.bytesRead},bytesWrit:${app.user.bytesWrit}) used by user ${app.user.id.UUID.toString("hex")}`, 1);
if (app.user.expire && app.user.expire < new Date().getTime()) {
return log(`expire user ${app.user.id.UUID.toString("hex")}`, 1)
}
app._adBuf.put(buffer, app);
}

@@ -247,3 +254,3 @@ }

} catch (error) {
log(error)
onerror(app, error)
}

@@ -254,13 +261,15 @@ }

const app = this.app
if (!app._isHeaderSent) {
app._isHeaderSent = true;
const header = EncodeResponseHeader(app)
app.user.bytesRead += buffer.length
const chunks = common.getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
this.localMessage(header)
this.localMessage(Buffer.concat([...chunks]))
} else {
app.user.bytesRead += buffer.length
const chunks = common.getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
this.localMessage(Buffer.concat(chunks))
if (app) {
if (!app._isHeaderSent) {
app._isHeaderSent = true;
const header = EncodeResponseHeader(app)
app.user.bytesRead += buffer.length
const chunks = common.getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
this.localMessage(header)
this.localMessage(Buffer.concat([...chunks]))
} else {
app.user.bytesRead += buffer.length
const chunks = common.getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
this.localMessage(Buffer.concat(chunks))
}
}

@@ -272,3 +281,3 @@ }

if (data === null) {
return log("fail to decrypt data chunk", 1);
return onerror(app, "fail to decrypt data chunk", 1);
}

@@ -332,24 +341,30 @@ app.user.bytesWrit += data.length

function onclose() {
if (this.app.remote)
this.app.remote.close()
this.app.remote = null
function onerror(app, error, ind) {
onclose(app);
log(error, ind)
}
this.app._isConnecting = false;
this.app._isHeaderSent = false;
this.app._isHeaderRecv = false;
if (this.app._adBuf)
this.app._adBuf.clear();
this.app._adBuf = null;
this.app._host = null;
this.app._port = null;
this.app._staging = null;
this.app._dataEncKey = null;
this.app._dataEncKeyForChaCha20 = null;
this.app._dataEncIV = null;
this.app._dataDecKey = null;
this.app._dataDecKeyForChaCha20 = null;
this.app._dataDecIV = null;
this.app._chunkLenEncMaskGenerator = null;
this.app._chunkLenDecMaskGenerator = null;
function onclose(app) {
if (app.remote)
app.remote.close()
app.remote = null
app._isConnecting = false;
app._isHeaderSent = false;
app._isHeaderRecv = false;
if (app._adBuf)
app._adBuf.clear();
app._adBuf = null;
app._option = null
app._host = null;
app._port = null;
app._staging = null;
app._dataEncKey = null;
app._dataEncKeyForChaCha20 = null;
app._dataEncIV = null;
app._dataDecKey = null;
app._dataDecKeyForChaCha20 = null;
app._dataDecIV = null;
app._chunkLenEncMaskGenerator = null;
app._chunkLenDecMaskGenerator = null;
}

@@ -356,0 +371,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc