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 1.2.1 to 1.2.2

protocols/vmess/common.js

12

index.js

@@ -21,3 +21,3 @@

if (!data.outbound)
throw ("outbound is not defined")
throw ("outbound is not defined (in bridge mode outbound must be defined)")
if (data.outbound.protocol)

@@ -33,10 +33,12 @@ throw ("do not use outbound protocol in bridge mode")

for (const i of data.inbounds) {
localNetwork(i.networks, protocols[i.protocol].server(i.users, freedom))
if (!i.protocol || !(i.protocol in protocols))
throw ("inbound protocol is not defined")
localNetwork(i.networks, protocols[i.protocol].server(i, freedom))
}
} else {
var remoteProtocol = protocols[data.outbound.protocol].client(data.outbound.user, remoteNetwork(data.outbound.network.type))
var remoteProtocol = protocols[data.outbound.protocol].client(data.outbound, remoteNetwork(data.outbound.network.type))
for (const i of data.inbounds) {
if (!i.protocol)
if (!i.protocol || !(i.protocol in protocols))
throw ("inbound protocol is not defined")
localNetwork(i.networks, protocols[i.protocol].server(i.users, remoteProtocol))
localNetwork(i.networks, protocols[i.protocol].server(i, remoteProtocol))
}

@@ -43,0 +45,0 @@ }

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

@@ -23,12 +23,13 @@ "main": "index.js",

"license": "MIT",
"homepage": "https://github.com/seezaara/js2ray",
"repository": {
"type": "git",
"url": "https://github.com/seezaara/js2ray.git"
},
"dependencies": {
"cbor-js": "^0.1.0",
"cuckoo-filter": "^1.1.4",
"libsodium-wrappers": "^0.7.11",
"ws": "^8.12.0"
},
"homepage": "https://github.com/seezaara/js2ray",
"repository": {
"type": "git",
"url": "https://github.com/seezaara/js2ray.git"
}
}
}

@@ -85,13 +85,13 @@

function user(inp, del) {
function user(tag, inp, del) {
if (typeof inp == 'object') {
addUser(a)
addUser(tag, a)
save()
} else if (typeof inp == "string") {
var sub_user = []
for (var i in users) {
if (users[i].email == inp) {
sub_user.push(users[i])
for (var i in usersp[tag]) {
if (usersp[tag][i].email == inp) {
sub_user.push(usersp[tag][i])
if (del)
users.splice(i, 1)
usersp[tag].splice(i, 1)
}

@@ -101,24 +101,30 @@ }

} else if (inp == undefined) {
return users;
return usersp[tag];
}
}
function AsAccount(u) {
function AsAccount(tag, data_user) {
if (tag == undefined)
tag = (Math.random() + 1).toString(36).substring(3)
if (users[tag] == undefined)
users[tag] = []
var users_ids = []
for (var i in users) {
users_ids.push(users[i].id.UUID.toString())
for (var i in users[tag]) {
users_ids.push(users[tag][i].id.UUID.toString())
}
for (var i of u) {
for (var i of data_user) {
if (!users_ids.includes(ParseString(i.id).toString())) {
addUser(i, true)
addUser(tag, i)
}
}
save()
return users;
return users[tag];
}
function addUser(a) {
function addUser(tag, a) {
var protoID = NewID(ParseString(a.id))
if (!a.alterId)
a.alterId = 0
var user = {

@@ -136,3 +142,3 @@ id: protoID,

}
users.push(user)
users[tag].push(user)
return user

@@ -144,6 +150,7 @@ }

function usesave() {
return {}
try {
var usage = fs.readFileSync(__dirname + "/data.json");
if (usage == "") {
usage = []
usage = {}
} else {

@@ -164,3 +171,3 @@ usage = JSON.parse(usage)

throw Error("read file error: ")
return []
return {}
}

@@ -167,0 +174,0 @@ }

@@ -21,2 +21,11 @@

function CreateAuthID(cmdKey, time) {
var buf = Buffer.alloc(16)
buf.writeBigUInt64BE(BigInt(time), 0)
buf.writeInt32BE(Math.floor(Math.random() * 147483647), 8)
buf.writeUInt32BE(CRC32(buf.subarray(0, 12)), 12)
var aesBlock = kdf.KDF16(cmdKey, consts.KDFSaltConstAuthIDEncryptionKey)
return kdf.encrypt(buf, aesBlock)
}
function Decode(aidd, data) {

@@ -32,2 +41,5 @@ data = kdf.decrypt(data, aidd)

function unix() {
return Math.round(new Date() / 1000)
}
function Match(AuthIDDecoderHolder, authID) {

@@ -43,3 +55,3 @@ for (var v in AuthIDDecoderHolder.decoders) {

if (Math.abs(Number(decode.t) - (Math.round(new Date() / 1000))) > 120) {
if (Math.abs(Number(decode.t) - unix()) > 120) {
continue

@@ -80,3 +92,2 @@ }

// =============================

@@ -106,2 +117,49 @@ var payloadHeaderAEADKey = kdf.KDF16(key, consts.KDFSaltConstVMessHeaderPayloadAEADKey, authid, nonce)

function SealVMessAEADHeader(key, data) {
const generatedAuthID = CreateAuthID(key, unix())
const connectionNonce = crypto.randomBytes(8)
const aeadPayloadLengthSerializeBuffer = new Buffer.alloc(2);
aeadPayloadLengthSerializeBuffer.writeUInt16BE(data.length, 0);
// ==================================
var payloadHeaderLengthAEADKey = kdf.KDF16(key, consts.KDFSaltConstVMessHeaderPayloadLengthAEADKey, generatedAuthID, connectionNonce)
var payloadHeaderLengthAEADNonce = kdf.KDF(key, consts.KDFSaltConstVMessHeaderPayloadLengthAEADIV, generatedAuthID, connectionNonce).subarray(0, 12)
try {
const cipher = crypto.createCipheriv('aes-128-gcm', payloadHeaderLengthAEADKey, payloadHeaderLengthAEADNonce);
cipher.setAAD(generatedAuthID);
var payloadHeaderLengthAEADEncrypted = Buffer.concat([cipher.update(aeadPayloadLengthSerializeBuffer), cipher.final(), cipher.getAuthTag()])
} catch (error) {
log(error)
return
}
// ==================================
var payloadHeaderAEADKey = kdf.KDF16(key, consts.KDFSaltConstVMessHeaderPayloadAEADKey, generatedAuthID, connectionNonce)
var payloadHeaderAEADNonce = kdf.KDF(key, consts.KDFSaltConstVMessHeaderPayloadAEADIV, generatedAuthID, connectionNonce).subarray(0, 12)
try {
const cipher = crypto.createCipheriv('aes-128-gcm', payloadHeaderAEADKey, payloadHeaderAEADNonce);
cipher.setAAD(generatedAuthID);
var payloadHeaderAEADEncrypted = Buffer.concat([cipher.update(data), cipher.final(), cipher.getAuthTag()])
} catch (error) {
log(error)
return
}
// ===========================
return Buffer.concat([
generatedAuthID,
payloadHeaderLengthAEADEncrypted,
connectionNonce,
payloadHeaderAEADEncrypted
])
}
// ====================================================== FUNCTIONS

@@ -113,3 +171,4 @@

Match,
OpenVMessAEADHeader
OpenVMessAEADHeader,
SealVMessAEADHeader
}
const common = require("./common")
const validator = require("./validator")
const consts = require("./consts")
const AdvancedBuffer = require("./advanced-buffer")
const kdf = require("./kdf")
const net = require("net")
const ipparser = require("ip")
const crypto = require("crypto");

@@ -12,16 +16,37 @@ const ATYP_V4 = 0x01;

function init(users, remoteProtocol) {
var checkuser = validator.init([users])
return function (address, port, cmd, remoteConnect, remoteMessage, remoteClose) {
var app = {}
function init(data, remoteNetwork) {
var randomuser = validator.init(data).get
return function (address, port, cmd, localConnect, localMessage, localClose) {
const app = {}
app.localMessage = localMessage
app.user = {}
app._cmd = cmd;
app._port = common.ntb(port);
const type = getAddrType(address);
app._atyp = type;
app._port = ntb(port);
app._host = (type === ATYP_DOMAIN) ? Buffer.from(address) : ipparser.toBuffer(address);
EncodeRequestHeader(cmd)
app._host = (type === ATYP_DOMAIN) ? Buffer.from(address) : toBuffer(address);
app._adBuf = new AdvancedBuffer({ getPacketLength: onReceivingLength.bind(app) });
app._adBuf.on('data', EncodeRequestBody.bind(app));
app._staging = Buffer.alloc(0)
app._option = 0x05
app._cipherNonce = 0;
app._decipherNonce = 0;
app._adBuf = new AdvancedBuffer({ getPacketLength: onReceivingLength });
app._adBuf.on('data', DecodeResponseBody);
var socket = remoteNetwork(
data.network.address,
data.network.port,
data.network.option,
localConnect,
DecodeResponseHeader.bind(app),
localClose,
)
socket.app = app
return {
message: EncodeRequestHeader,
message: EncodeRequestBody.bind(socket, randomuser),
close: onclose.bind(socket),

@@ -32,52 +57,85 @@ }

function onclose() {
this.close()
const app = this.app
app._isConnecting = false;
app._isHeaderSent = false;
app._isHeaderRecv = false;
function getAddrType(host) {
if (net.isIPv4(host)) {
return ATYP_V4;
app._adBuf.clear();
app._adBuf = 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;
}
function EncodeRequestBody(randomuser, buffer) {
const app = this.app
if (!app._isHeaderSent) {
app._isHeaderSent = true;
const header = EncodeRequestHeader(app, randomuser)
app.user.bytesRead += buffer.length
const chunks = getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
this.message(Buffer.concat([header, ...chunks]))
} else {
app.user.bytesRead += buffer.length
const chunks = getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
this.message(Buffer.concat(chunks))
}
if (net.isIPv6(host)) {
return ATYP_V6;
}
return ATYP_DOMAIN;
}
function EncodeRequestHeader(app, cmd) {
function EncodeRequestHeader(app, randomuser) {
const rands = crypto.randomBytes(33);
const [isAEAD, random_user, authInfo, ts] = randomuser();
app._isAEADRequest = isAEAD
app.user = random_user
// IV and Key for data chunks encryption/decryption
app._dataEncIV = rands.slice(0, 16);
app._dataEncKey = rands.slice(16, 32);
app._dataDecIV = hash('md5', app._dataEncIV);
app._dataDecKey = hash('md5', app._dataEncKey);
app._dataEncIV = rands.subarray(0, 16);
app._dataEncKey = rands.subarray(16, 32);
app._dataEncKeyForChaCha20 = createChacha20Poly1305Key(app._dataEncKey);
app._dataDecKeyForChaCha20 = createChacha20Poly1305Key(app._dataDecKey);
if (isAEAD) {
app._dataDecIV = common.hash('sha256', app._dataEncIV).subarray(0, 16);
app._dataDecKey = common.hash('sha256', app._dataEncKey).subarray(0, 16);
} else {
app._dataDecIV = common.hash('md5', app._dataEncIV);
app._dataDecKey = common.hash('md5', app._dataEncKey);
}
app._chunkLenEncMaskGenerator = shake128(app._dataEncIV);
app._chunkLenDecMaskGenerator = shake128(app._dataDecIV);
app._dataEncKeyForChaCha20 = common.createChacha20Poly1305Key(app._dataEncKey);
app._dataDecKeyForChaCha20 = common.createChacha20Poly1305Key(app._dataDecKey);
app._chunkLenEncMaskGenerator = common.shake128(app._dataEncIV);
app._chunkLenDecMaskGenerator = common.shake128(app._dataDecIV);
app._v = rands[32];
app._opt = 0x05;
app._option = 0x05;
const uuid = app._uuid;
const { userHashCache } = app.getStore();
const paddingLen = getRandomInt(0, 15);
const padding = crypto.randomBytes(paddingLen);
const { timestamp, authInfo } = userHashCache[getRandomInt(0, userHashCache.length - 1)];
// utc timestamp: Big-Endian, 8 bytes
const ts = uint64ToBuffer(timestamp);
app._security = app.user.security || 2
const paddingLen = getRandomInt(0, 15);
const padding = crypto.randomBytes(paddingLen);
// create encrypted command
let command = Buffer.from([
0x01, // Ver
...app._dataEncIV, ...app._dataEncKey, app._v, app._opt,
...app._dataEncIV, ...app._dataEncKey, app._v, app._option,
paddingLen << 4 | app._security,
0x00, // RSV
cmd, // Cmd
...app._port, app._atyp,
app._cmd, // Cmd
...app._port,
app._atyp,
...Buffer.concat([
(app._atyp === ATYP_DOMAIN) ? ntb(app._host.length, 1) : Buffer.alloc(0),
(app._atyp === ATYP_DOMAIN) ? common.ntb(app._host.length, 1) : Buffer.alloc(0),
app._host,

@@ -87,91 +145,77 @@ ]),

]);
command = Buffer.concat([command, fnv1a(command)]);
const cipher = crypto.createCipheriv(
'aes-128-cfb',
hash('md5', Buffer.concat([uuid, Buffer.from('c48619fe-8f02-49e0-b9e9-edf763e17e21')])),
hash('md5', Buffer.concat([ts, ts, ts, ts])),
);
command = cipher.update(command);
return Buffer.concat([authInfo, command]);
}
command = Buffer.concat([command, common.fnv1a(command)]);
function onclose() {
if (this.app.remote)
this.app.remote.close()
this.app._isConnecting = false;
this.app._isHeaderSent = false;
this.app._isHeaderRecv = false;
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;
}
// onInitTargetAddress({ host, port }) {
// const type = getAddrType(host);
// this._atyp = type;
// this._port = ntb(port);
// this._host = (type === ATYP_DOMAIN) ? Buffer.from(host) : ip.toBuffer(host);
// }
function EncodeRequestBody(buffer) {
const app = this.app
app.user.bytesRead += buffer.length
if (!app._isHeaderSent) {
app._isHeaderSent = true;
this.write(EncodeRequestHeader(app))
const chunks = getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
for (const iterator of chunks) {
this.write(iterator)
if (isAEAD == false) {
const cipher = crypto.createCipheriv(
'aes-128-cfb',
random_user.id.cmdKey,
common.hash('md5', Buffer.concat([ts, ts, ts, ts])),
);
command = cipher.update(command);
return Buffer.concat([authInfo, command]);
} else if (typeof random_user == "object") {
var cipher = validator.SealVMessAEADHeader(random_user.id.cmdKey, command)
if (cipher == undefined) {
return log("AEAD read failed")
}
return cipher;
} else {
const chunks = getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
for (const iterator of chunks) {
this.write(iterator)
}
return log(`invalid user`);
}
}
function DecodeResponseHeader(app) {
var outBuffer = Buffer.from([app._responseHeader, 0x00, 0x00, 0x00])
if (!app._isAEADRequest) {
var encryptionWriter = crypto.createCipheriv('aes-128-cfb', app._dataEncKey, app._dataEncIV);
return encryptionWriter.update(outBuffer);
} else {
const aeadResponseHeaderLengthEncryptionKey = kdf.KDF16(app._dataEncKey, consts.KDFSaltConstAEADRespHeaderLenKey)
const aeadResponseHeaderLengthEncryptionIV = kdf.KDF(app._dataEncIV, consts.KDFSaltConstAEADRespHeaderLenIV).subarray(0, 12)
const aeadResponseHeaderLengthEncryptionBuffer = Buffer.allocUnsafe(2);
aeadResponseHeaderLengthEncryptionBuffer.writeUInt16BE(outBuffer.length)
const cipher = crypto.createCipheriv('aes-128-gcm', aeadResponseHeaderLengthEncryptionKey, aeadResponseHeaderLengthEncryptionIV);
var AEADEncryptedLength = Buffer.concat([cipher.update(aeadResponseHeaderLengthEncryptionBuffer), cipher.final(), cipher.getAuthTag()])
function DecodeResponseHeader(buffer) {
const app = this
if (!app._isHeaderRecv) {
if (app._dataDecKey == null)
return
try {
if (!app._isAEADRequest) {
const decipher = crypto.createDecipheriv('aes-128-cfb', app._dataDecKey, app._dataDecIV);
var header = decipher.update(buffer.subarray(0, 4));
} else {
const aeadResponseHeaderLengthEncryptionKey = kdf.KDF16(app._dataDecKey, consts.KDFSaltConstAEADRespHeaderLenKey)
const aeadResponseHeaderLengthEncryptionIV = kdf.KDF(app._dataDecIV, consts.KDFSaltConstAEADRespHeaderLenIV).subarray(0, 12)
const decipher = crypto.createDecipheriv('aes-128-gcm', aeadResponseHeaderLengthEncryptionKey, aeadResponseHeaderLengthEncryptionIV);
const aeadEncryptedResponseHeaderLength = buffer.subarray(0, 2)
const aeadEncryptedResponseHeaderLengthTag = buffer.subarray(2, 18)
const aeadResponseHeaderPayloadEncryptionKey = kdf.KDF16(app._dataEncKey, consts.KDFSaltConstAEADRespHeaderPayloadKey)
const aeadResponseHeaderPayloadEncryptionIV = kdf.KDF(app._dataEncIV, consts.KDFSaltConstAEADRespHeaderPayloadIV).subarray(0, 12)
decipher.setAuthTag(aeadEncryptedResponseHeaderLengthTag);
const decryptedAEADHeaderLengthPayloadResult = Buffer.concat([decipher.update(aeadEncryptedResponseHeaderLength), decipher.final()])
const decryptedResponseHeaderLength = decryptedAEADHeaderLengthPayloadResult.readUInt16BE(0) + 18
const cipher2 = crypto.createCipheriv('aes-128-gcm', aeadResponseHeaderPayloadEncryptionKey, aeadResponseHeaderPayloadEncryptionIV);
const aeadResponseHeaderPayloadEncryptionKey = kdf.KDF16(app._dataDecKey, consts.KDFSaltConstAEADRespHeaderPayloadKey)
const aeadResponseHeaderPayloadEncryptionIV = kdf.KDF(app._dataDecIV, consts.KDFSaltConstAEADRespHeaderPayloadIV).subarray(0, 12)
var aeadEncryptedHeaderPayload = Buffer.concat([cipher2.update(outBuffer), cipher2.final(), cipher2.getAuthTag()])
return Buffer.concat([AEADEncryptedLength, aeadEncryptedHeaderPayload])
const decipher2 = crypto.createDecipheriv('aes-128-gcm', aeadResponseHeaderPayloadEncryptionKey, aeadResponseHeaderPayloadEncryptionIV);
const encryptedResponseHeaderBuffer = buffer.subarray(18, decryptedResponseHeaderLength)
const encryptedResponseHeaderBufferTag = buffer.subarray(decryptedResponseHeaderLength, decryptedResponseHeaderLength + 16)
decipher2.setAuthTag(encryptedResponseHeaderBufferTag);
var header = Buffer.concat([decipher2.update(encryptedResponseHeaderBuffer), decipher2.final()])
}
} catch (error) {
return log(error)
}
if (app._v !== header[0]) {
return fail(`server response v doesn't match, expect ${app._v} but got ${header[0]}`);
}
app._isHeaderRecv = true;
return app._adBuf.put(buffer.subarray(4 + header[3]), app);
}
app._adBuf.put(buffer, app);
}
function DecodeResponseBody(chunk, app) {
if ([consts.SECURITY_TYPE_AES_128_GCM, consts.SECURITY_TYPE_CHACHA20_POLY1305].includes(this._security)) {
const tag = chunk.slice(-16);
const data = decrypt.call(app, chunk.slice(2, -16), tag);
if ([consts.SECURITY_TYPE_AES_128_GCM, consts.SECURITY_TYPE_CHACHA20_POLY1305].includes(app._security)) {
const data = common.decrypt(chunk.subarray(2), app);
if (data === null) {

@@ -181,25 +225,40 @@ return log(`fail to verify data chunk, `, chunk + "");

app.user.bytesWrit += data.length
if (app.remoteWrite)
return app.remoteWrite(data);
if (app.localMessage)
return app.localMessage(data);
}
app.user.bytesWrit += chunk.length - 2
if (app.remoteWrite)
return app.remoteWrite(chunk.slice(2));
if (app.localMessage)
return app.localMessage(chunk.subarray(2));
}
// ================================================= sender
// ================================================= functions
function resolveChunk(chunk) {
console.log(100000);
let _chunk = chunk;
if ([consts.SECURITY_TYPE_AES_128_GCM, consts.SECURITY_TYPE_CHACHA20_POLY1305].includes(this._security)) {
_chunk = Buffer.concat(encrypt(_chunk));
_chunk = common.encrypt(_chunk, this);
}
let _len = _chunk.length;
if (this._option & 4 !== 0) {
if (this._option >= 0x05) {
const mask = this._chunkLenEncMaskGenerator.nextBytes(2).readUInt16BE(0);
_len = mask ^ _len;
}
return Buffer.concat([ntb(_len), _chunk]);
console.log(10, this._option, _len)
return Buffer.concat([common.ntb(_len), _chunk]);
}
function onReceivingLength(buffer, app) {
if (buffer.length < 2) {
return;
}
let len = buffer.readUInt16BE(0);
if (app._option >= 0x05) {
const mask = app._chunkLenDecMaskGenerator.nextBytes(2).readUInt16BE(0);
len = mask ^ len;
}
console.log(20,app._option, len)
return 2 + len;
}
function getChunks(buffer, maxSize) {

@@ -210,7 +269,7 @@ const totalLen = buffer.length;

while (ptr < totalLen - 1) {
bufs.push(buffer.slice(ptr, ptr + maxSize));
bufs.push(buffer.subarray(ptr, ptr + maxSize));
ptr += maxSize;
}
if (ptr < totalLen) {
bufs.push(buffer.slice(ptr));
bufs.push(buffer.subarray(ptr));
}

@@ -220,14 +279,78 @@ return bufs;

function onReceivingLength(buffer) {
if (buffer.length < 2) {
return;
const ipv4Regex = /^(\d{1,3}\.){3,3}\d{1,3}$/;
const ipv6Regex = /^(::)?(((\d{1,3}\.){3}(\d{1,3}){1})?([0-9a-f]){0,4}:{0,2}){1,8}(::)?$/i;
function toBuffer(ip, buff, offset) {
offset = ~~offset;
let result;
if (ipv4Regex.test(ip)) {
result = buff || Buffer.alloc(offset + 4);
ip.split(/\./g).map((byte) => {
result[offset++] = parseInt(byte, 10) & 0xff;
});
} else if (ipv6Regex.test(ip)) {
const sections = ip.split(':', 8);
let i;
for (i = 0; i < sections.length; i++) {
const isv4 = ipv4Regex.test(sections[i]);
let v4Buffer;
if (isv4) {
v4Buffer = this.toBuffer(sections[i]);
sections[i] = v4Buffer.subarray(0, 2).toString('hex');
}
if (v4Buffer && ++i < 8) {
sections.splice(i, 0, v4Buffer.subarray(2, 4).toString('hex'));
}
}
if (sections[0] === '') {
while (sections.length < 8) sections.unshift('0');
} else if (sections[sections.length - 1] === '') {
while (sections.length < 8) sections.push('0');
} else if (sections.length < 8) {
for (i = 0; i < sections.length && sections[i] !== ''; i++);
const argv = [i, 1];
for (i = 9 - sections.length; i > 0; i--) {
argv.push('0');
}
sections.splice(...argv);
}
result = buff || Buffer.alloc(offset + 16);
for (i = 0; i < sections.length; i++) {
const word = parseInt(sections[i], 16);
result[offset++] = (word >> 8) & 0xff;
result[offset++] = word & 0xff;
}
}
let len = buffer.readUInt16BE(0);
if (this._option & 4 !== 0) {
const mask = this._chunkLenDecMaskGenerator.nextBytes(2).readUInt16BE(0);
len = mask ^ len;
if (!result) {
throw Error(`Invalid ip address: ${ip}`);
}
return 2 + len;
return result;
};
function getAddrType(host) {
if (net.isIPv4(host)) {
return ATYP_V4;
}
if (net.isIPv6(host)) {
return ATYP_V6;
}
return ATYP_DOMAIN;
}
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.ceil(max);
const random = crypto.randomBytes(1)[0] / (0xff + 1e-13);
return Math.floor(random * (max - min + 1) + min);
}
module.exports = init

@@ -5,5 +5,4 @@

server: require('./server'),
// client: require('./client'),
client: {},
client: require('./client'),
user: account.user
}
const common = require("./common")
const validator = require("./validator")
const AdvancedBuffer = require("./advanced-buffer")
const jsSha = require("./crypto/sha3");
const kdf = require("./kdf")

@@ -16,3 +16,3 @@ const event = require("../../event")

function init(users, remoteProtocol) {
var checkuser = validator.init(users)
var checkuser = validator.init(users).check
return function (socket, ip) {

@@ -29,4 +29,4 @@ socket.app = {}

socket.app._adBuf = new AdvancedBuffer({ getPacketLength: onReceivingLength.bind(socket.app) });
socket.app._adBuf.on('data', DecodeRequestBody.bind(socket.app));
socket.app._adBuf = new AdvancedBuffer({ getPacketLength: onReceivingLength });
socket.app._adBuf.on('data', DecodeRequestBody);

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

function DecodeRequestHeader(remoteProtocol, onRemoteMessage, onRemoteClose, checkuser, buffer) {
const app = this.app

@@ -63,4 +64,4 @@ if (!app._isHeaderRecv) {

aeadUser = user[0]
var iv = hash('md5', Buffer.concat([ts, ts, ts, ts]))
var decipher = crypto.createDecipheriv('aes-128-cfb', aeadUser.id.cmdKey, iv);
var decipher = crypto.createDecipheriv('aes-128-cfb', aeadUser.id.cmdKey,
common.hash('md5', Buffer.concat([ts, ts, ts, ts])));
decipher.subarray = function (a, b) {

@@ -104,17 +105,13 @@ return this.update(reqCommand.subarray(a, b))

if (app._isAEADRequest) {
app._dataEncIV = hash('sha256', app._dataDecIV).subarray(0, 16);
app._dataEncKey = hash('sha256', app._dataDecKey).subarray(0, 16);
app._dataEncIV = common.hash('sha256', app._dataDecIV).subarray(0, 16);
app._dataEncKey = common.hash('sha256', app._dataDecKey).subarray(0, 16);
} else {
app._dataEncIV = hash('md5', app._dataDecIV);
app._dataEncKey = hash('md5', app._dataDecKey);
app._dataEncIV = common.hash('md5', app._dataDecIV);
app._dataEncKey = common.hash('md5', app._dataDecKey);
}
app._dataDecKeyForChaCha20 = createChacha20Poly1305Key(app._dataDecKey);
app._dataEncKeyForChaCha20 = createChacha20Poly1305Key(app._dataEncKey);
app._chunkLenDecMaskGenerator = shake128(app._dataDecIV);
app._chunkLenEncMaskGenerator = shake128(app._dataEncIV);
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'

@@ -179,3 +176,3 @@ // 3 'aes-128-gcm'

if (fnv1a(plainReqHeader).equals(f)) {
if (common.fnv1a(plainReqHeader).equals(f)) {
return log('fail to verify request command');

@@ -186,3 +183,2 @@ }

app._isConnecting = true;
app.remote = remoteProtocol(

@@ -209,9 +205,8 @@ addrType === ATYP_DOMAIN ? addr.toString() : iptoString(addr),

}
function DecodeRequestBody(chunk) {
var app = this
function DecodeRequestBody(chunk, app) {
if ([consts.SECURITY_TYPE_AES_128_GCM, consts.SECURITY_TYPE_CHACHA20_POLY1305].includes(app._security)) {
const tag = chunk.slice(-16);
const data = decrypt.call(app, chunk.slice(2, -16), tag);
const data = common.decrypt(chunk.subarray(2), app);
if (data === null) {
return log(`fail to verify data chunk, `, chunk + "");
return log("fail to verify data chunk");
}

@@ -224,3 +219,3 @@ app.user.bytesWrit += data.length

if (app.remote)
return app.remote.message(chunk.slice(2));
return app.remote.message(chunk.subarray(2));
}

@@ -230,24 +225,28 @@

var outBuffer = Buffer.from([app._responseHeader, 0x00, 0x00, 0x00])
if (!app._isAEADRequest) {
var encryptionWriter = crypto.createCipheriv('aes-128-cfb', app._dataEncKey, app._dataEncIV);
return encryptionWriter.update(outBuffer);
} else {
const aeadResponseHeaderLengthEncryptionKey = kdf.KDF16(app._dataEncKey, consts.KDFSaltConstAEADRespHeaderLenKey)
const aeadResponseHeaderLengthEncryptionIV = kdf.KDF(app._dataEncIV, consts.KDFSaltConstAEADRespHeaderLenIV).subarray(0, 12)
const aeadResponseHeaderLengthEncryptionBuffer = Buffer.allocUnsafe(2);
aeadResponseHeaderLengthEncryptionBuffer.writeUInt16BE(outBuffer.length)
try {
if (!app._isAEADRequest) {
var encryptionWriter = crypto.createCipheriv('aes-128-cfb', app._dataEncKey, app._dataEncIV);
return encryptionWriter.update(outBuffer);
} else {
const cipher = crypto.createCipheriv('aes-128-gcm', aeadResponseHeaderLengthEncryptionKey, aeadResponseHeaderLengthEncryptionIV);
var AEADEncryptedLength = Buffer.concat([cipher.update(aeadResponseHeaderLengthEncryptionBuffer), cipher.final(), cipher.getAuthTag()])
const aeadResponseHeaderLengthEncryptionKey = kdf.KDF16(app._dataEncKey, consts.KDFSaltConstAEADRespHeaderLenKey)
const aeadResponseHeaderLengthEncryptionIV = kdf.KDF(app._dataEncIV, consts.KDFSaltConstAEADRespHeaderLenIV).subarray(0, 12)
const aeadResponseHeaderLengthEncryptionBuffer = Buffer.alloc(2);
aeadResponseHeaderLengthEncryptionBuffer.writeUInt16BE(outBuffer.length)
const cipher = crypto.createCipheriv('aes-128-gcm', aeadResponseHeaderLengthEncryptionKey, aeadResponseHeaderLengthEncryptionIV);
var AEADEncryptedLength = Buffer.concat([cipher.update(aeadResponseHeaderLengthEncryptionBuffer), cipher.final(), cipher.getAuthTag()])
const aeadResponseHeaderPayloadEncryptionKey = kdf.KDF16(app._dataEncKey, consts.KDFSaltConstAEADRespHeaderPayloadKey)
const aeadResponseHeaderPayloadEncryptionIV = kdf.KDF(app._dataEncIV, consts.KDFSaltConstAEADRespHeaderPayloadIV).subarray(0, 12)
const aeadResponseHeaderPayloadEncryptionKey = kdf.KDF16(app._dataEncKey, consts.KDFSaltConstAEADRespHeaderPayloadKey)
const aeadResponseHeaderPayloadEncryptionIV = kdf.KDF(app._dataEncIV, consts.KDFSaltConstAEADRespHeaderPayloadIV).subarray(0, 12)
const cipher2 = crypto.createCipheriv('aes-128-gcm', aeadResponseHeaderPayloadEncryptionKey, aeadResponseHeaderPayloadEncryptionIV);
const cipher2 = crypto.createCipheriv('aes-128-gcm', aeadResponseHeaderPayloadEncryptionKey, aeadResponseHeaderPayloadEncryptionIV);
var aeadEncryptedHeaderPayload = Buffer.concat([cipher2.update(outBuffer), cipher2.final(), cipher2.getAuthTag()])
return Buffer.concat([AEADEncryptedLength, aeadEncryptedHeaderPayload])
var aeadEncryptedHeaderPayload = Buffer.concat([cipher2.update(outBuffer), cipher2.final(), cipher2.getAuthTag()])
return Buffer.concat([AEADEncryptedLength, aeadEncryptedHeaderPayload])
}
} catch (error) {
log(error)
}

@@ -261,16 +260,39 @@ }

app._isHeaderSent = true;
this.localMessage(EncodeResponseHeader(app))
const header = EncodeResponseHeader(app)
const chunks = getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
for (const iterator of chunks) {
this.localMessage(iterator)
}
this.localMessage(Buffer.concat([header, ...chunks]))
} else {
const chunks = getChunks(buffer, 0x3fff).map(resolveChunk.bind(app));
for (const iterator of chunks) {
this.localMessage(iterator)
}
this.localMessage(Buffer.concat(chunks))
}
}
function resolveChunk(chunk) {
let _chunk = chunk;
if ([consts.SECURITY_TYPE_AES_128_GCM, consts.SECURITY_TYPE_CHACHA20_POLY1305].includes(this._security)) {
_chunk = common.encrypt(_chunk, this)
}
let _len = _chunk.length;
if (this._option >= 0x05) {
const mask = this._chunkLenEncMaskGenerator.nextBytes(2).readUInt16BE(0);
_len = mask ^ _len;
}
console.log(10, this._option, _len)
return Buffer.concat([common.ntb(_len), _chunk]);
}
function onReceivingLength(buffer, app) {
if (buffer.length < 2) {
return;
}
let len = buffer.readUInt16BE(0);
if (app._option >= 0x05) {
var mask = app._chunkLenDecMaskGenerator.nextBytes(2).readUInt16BE(0);
len = mask ^ len;
}
console.log(20, app._option, len)
return 2 + len;
}
function onclose() {

@@ -300,15 +322,2 @@ if (this.app.remote)

// ================================================= sender
function resolveChunk(chunk) {
let _chunk = chunk;
if ([consts.SECURITY_TYPE_AES_128_GCM, consts.SECURITY_TYPE_CHACHA20_POLY1305].includes(this._security)) {
_chunk = Buffer.concat(encrypt(_chunk));
}
let _len = _chunk.length;
if (this._option & 4 !== 0) {
const mask = this._chunkLenEncMaskGenerator.nextBytes(2).readUInt16BE(0);
_len = mask ^ _len;
}
return Buffer.concat([ntb(_len), _chunk]);
}
function getChunks(buffer, maxSize) {

@@ -319,7 +328,7 @@ const totalLen = buffer.length;

while (ptr < totalLen - 1) {
bufs.push(buffer.slice(ptr, ptr + maxSize));
bufs.push(buffer.subarray(ptr, ptr + maxSize));
ptr += maxSize;
}
if (ptr < totalLen) {
bufs.push(buffer.slice(ptr));
bufs.push(buffer.subarray(ptr));
}

@@ -387,125 +396,4 @@ return bufs;

function encrypt(plaintext) {
const security = this._security;
const nonce = Buffer.concat([ntb(this._cipherNonce), this._dataEncIV.slice(2, 12)]);
let ciphertext = null;
let tag = null;
if (security === consts.SECURITY_TYPE_AES_128_GCM) {
const cipher = crypto.createCipheriv('aes-128-gcm', this._dataEncKey, nonce);
ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
tag = cipher.getAuthTag();
}
else if (security === consts.SECURITY_TYPE_CHACHA20_POLY1305) {
const noop = Buffer.alloc(0);
// eslint-disable-next-line
const result = libsodium.crypto_aead_chacha20poly1305_ietf_encrypt_detached(
plaintext, noop, noop, nonce, this._dataEncKeyForChaCha20,
);
ciphertext = Buffer.from(result.ciphertext);
tag = Buffer.from(result.mac);
}
this._cipherNonce += 1;
return [ciphertext, tag];
}
function decrypt(ciphertext, tag) {
const security = this._security;
const nonce = Buffer.concat([ntb(10), this._dataDecIV.slice(2, 12)]);
console.log(nonce)
if (security === consts.SECURITY_TYPE_AES_128_GCM) {
const decipher = crypto.createDecipheriv('aes-128-gcm', this._dataDecKey, nonce);
decipher.setAuthTag(tag);
try {
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
this._decipherNonce += 1;
return plaintext;
} catch (err) {
console.log(err)
return null;
}
}
else if (security === consts.SECURITY_TYPE_CHACHA20_POLY1305) {
const noop = Buffer.alloc(0);
try {
// eslint-disable-next-line
const plaintext = libsodium.crypto_aead_chacha20poly1305_ietf_decrypt_detached(
noop, ciphertext, tag, noop, nonce, this._dataDecKeyForChaCha20,
);
this._decipherNonce += 1;
return Buffer.from(plaintext);
} catch (err) {
return null;
}
}
}
function onReceivingLength(buffer) {
if (buffer.length < 2) {
return;
}
let len = buffer.readUInt16BE(0);
if (this._option & 4 !== 0) {
const mask = this._chunkLenDecMaskGenerator.nextBytes(2).readUInt16BE(0);
len = mask ^ len;
}
return 2 + len;
}
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);
}
return buf;
}
function hash(algorithm, buffer) {
const hs = crypto.createHash(algorithm);
hs.update(buffer);
return hs.digest();
}
function createChacha20Poly1305Key(key) {
const md5Key = hash('md5', key);
return Buffer.concat([md5Key, hash('md5', md5Key)]);
}
function shake128(buffer) {
let buffered = [];
let iter = 0;
return {
nextBytes: function nextBytes(n) {
if (iter + n > buffered.length) {
const hash = jsSha.shake128.create(buffered.length * 8 + 512);
hash.update(buffer);
buffered = Buffer.from(hash.arrayBuffer());
}
const bytes = buffered.subarray(iter, iter + n);
iter += n;
return bytes;
}
};
}
function fnv1a(buffer) {
let hash = 0x811c9dc5;
for (let i = 0; i < buffer.length; ++i) {
hash ^= buffer[i];
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
}
const buf = Buffer.alloc(4);
buf.writeUIntBE(hash >>> 0, 0, 4);
return buf;
}
module.exports = init
const crypto = require("crypto"),
long = require("./crypto/long"),
common = require("./common"),
_accont = require("./account"),

@@ -17,3 +17,3 @@ aead = require('./aead'),

for (const user of _accont.AsAccount(users_config)) {
for (const user of _accont.AsAccount(users_config.tag, users_config.users)) {
if (user.alterIDs.length == 0) {

@@ -43,3 +43,3 @@ aead.AddUser(AuthIDDecoderHolder, user.id.cmdKey, user)

function NewTimedUserValidator(AuthIDDecoderHolder, users) {
var tuv = {
const tuv = {
users: users,

@@ -56,8 +56,24 @@ userHash: {},

}
return function (authInfo, isaead) {
if (isaead)
return aead.Match(tuv.aeadDecoderHolder, authInfo)
else if (authInfo in tuv.userHash) {
const cacheItem = tuv.userHash[authInfo]
return [cacheItem.user.user, uint64ToBuffer(cacheItem.timeInc + tuv.baseTime)]
return {
get: function () {
const keys = Object.keys(tuv.aeadDecoderHolder.decoders)
if (keys.length != 0) {
const key = keys[Math.floor(Math.random() * keys.length)]
const cacheItem = tuv.aeadDecoderHolder.decoders[key]
return [true, cacheItem.ticket]
// return [true, cacheItem.ticket, Buffer.from(key, "hex")]
} else {
const keys = Object.keys(tuv.userHash)
const key = keys[Math.floor(Math.random() * keys.length)]
const cacheItem = tuv.userHash[key]
return [false, cacheItem.user.user, Buffer.from(key, "hex"), common.uint64ToBuffer(cacheItem.timeInc + tuv.baseTime)]
}
},
check: function (authInfo, isaead) {
if (isaead)
return aead.Match(tuv.aeadDecoderHolder, authInfo)
else if (authInfo in tuv.userHash) {
const cacheItem = tuv.userHash[authInfo]
return [cacheItem.user.user, common.uint64ToBuffer(cacheItem.timeInc + tuv.baseTime)]
}
}

@@ -76,3 +92,3 @@ }

for (var ts = genBeginSec; ts <= genEndSec; ts++) {
var hashValue = hasher('md5', id.UUID).update(uint64ToBuffer(ts)).digest("hex");
var hashValue = hasher('md5', id.UUID).update(common.uint64ToBuffer(ts)).digest("hex");
v.userHash[hashValue] = {

@@ -116,6 +132,2 @@ user: user,

function uint64ToBuffer(uint64, byteOrder = false /* BE */) {
const numbers = long.fromNumber(uint64, true).toBytes(byteOrder);
return Buffer.from(numbers);
}

@@ -150,3 +162,4 @@ function hasher(alg, key) {

Close,
OpenVMessAEADHeader: aead.OpenVMessAEADHeader
OpenVMessAEADHeader: aead.OpenVMessAEADHeader,
SealVMessAEADHeader: aead.SealVMessAEADHeader
}

@@ -8,2 +8,3 @@

}
function remoteNetwork(network) {

@@ -10,0 +11,0 @@ if (network == "tcp") {

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