Some more ChatGPT function optimizations
This commit is contained in:
@@ -188,56 +188,49 @@ class WTVSec {
|
|||||||
* @returns {CryptoJS.lib.WordArray} wtv-challenge-response (or blank if failed)
|
* @returns {CryptoJS.lib.WordArray} wtv-challenge-response (or blank if failed)
|
||||||
*/
|
*/
|
||||||
ProcessChallenge(wtv_challenge, key = this.current_shared_key) {
|
ProcessChallenge(wtv_challenge, key = this.current_shared_key) {
|
||||||
var challenge_raw = CryptoJS.enc.Base64.parse(wtv_challenge);
|
const challenge_raw = CryptoJS.enc.Base64.parse(wtv_challenge);
|
||||||
|
|
||||||
if (challenge_raw.sigBytes > 8) {
|
if (challenge_raw.sigBytes <= 8) {
|
||||||
var challenge_raw_hex = challenge_raw.toString(CryptoJS.enc.Hex);
|
throw new Error("Invalid challenge length");
|
||||||
var challenge_id_hex = challenge_raw_hex.substring(0, (8 * 2));
|
|
||||||
var challenge_enc_hex = challenge_raw_hex.substring((8*2));
|
|
||||||
var challenge_enc = CryptoJS.enc.Hex.parse(challenge_enc_hex);
|
|
||||||
|
|
||||||
var challenge_decrypted = CryptoJS.DES.decrypt(
|
|
||||||
{
|
|
||||||
ciphertext: challenge_enc
|
|
||||||
},
|
|
||||||
key,
|
|
||||||
{
|
|
||||||
mode: CryptoJS.mode.ECB,
|
|
||||||
padding: CryptoJS.pad.NoPadding
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
var challenge_dec_hex = challenge_decrypted.toString(CryptoJS.enc.Hex);
|
|
||||||
var challenge_md5_challenge = CryptoJS.MD5(CryptoJS.enc.Hex.parse(challenge_dec_hex.substring(0, (80 * 2))));
|
|
||||||
var test = challenge_dec_hex.substring((80 * 2), (96 * 2));
|
|
||||||
var test2 = challenge_md5_challenge.toString(CryptoJS.enc.Hex);
|
|
||||||
if (test == test2) {
|
|
||||||
this.current_shared_key = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((72*2), (80*2)));
|
|
||||||
var challenge_echo = CryptoJS.enc.Hex.parse(challenge_dec_hex.substr(0, (40*2)));
|
|
||||||
|
|
||||||
// RC4 encryption keys.Stored in the wtv-ticket on the server side.
|
|
||||||
this.session_key1 = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((40*2), (56*2)));
|
|
||||||
this.session_key2 = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((56*2), (72*2)));
|
|
||||||
|
|
||||||
var echo_encrypted = CryptoJS.DES.encrypt(CryptoJS.MD5(challenge_echo).concat(challenge_echo).concat(CryptoJS.enc.Utf8.parse("\x08".repeat(8))), this.current_shared_key, {
|
|
||||||
mode: CryptoJS.mode.ECB,
|
|
||||||
padding: CryptoJS.pad.NoPadding
|
|
||||||
});
|
|
||||||
|
|
||||||
// Last bytes is just extra padding
|
|
||||||
this.challenge_raw = challenge_raw;
|
|
||||||
this.challenge_key = this.current_shared_key;
|
|
||||||
var challenge_response = CryptoJS.enc.Hex.parse(challenge_raw_hex.substr(0, (8 * 2))).concat(echo_encrypted.ciphertext);
|
|
||||||
return challenge_response;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw ("Invalid challenge length");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const challenge_raw_hex = challenge_raw.toString(CryptoJS.enc.Hex);
|
||||||
|
const challenge_id_hex = challenge_raw_hex.substring(0, 16); // 8 bytes * 2
|
||||||
|
const challenge_enc = CryptoJS.enc.Hex.parse(challenge_raw_hex.substring(16));
|
||||||
|
|
||||||
|
const challenge_decrypted = CryptoJS.DES.decrypt(
|
||||||
|
{ ciphertext: challenge_enc },
|
||||||
|
key,
|
||||||
|
{ mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }
|
||||||
|
);
|
||||||
|
|
||||||
|
const challenge_dec_hex = challenge_decrypted.toString(CryptoJS.enc.Hex);
|
||||||
|
const challenge_md5_challenge = CryptoJS.MD5(CryptoJS.enc.Hex.parse(challenge_dec_hex.substring(0, 160))).toString(CryptoJS.enc.Hex); // 80 bytes * 2
|
||||||
|
|
||||||
|
if (challenge_dec_hex.substring(160, 192) !== challenge_md5_challenge) { // 96 bytes * 2
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.current_shared_key = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring(144, 160)); // 72 bytes * 2, 80 bytes * 2
|
||||||
|
const challenge_echo = CryptoJS.enc.Hex.parse(challenge_dec_hex.substr(0, 80)); // 40 bytes * 2
|
||||||
|
|
||||||
|
// RC4 encryption keys. Stored in the wtv-ticket on the server side.
|
||||||
|
this.session_key1 = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring(80, 112)); // 40 bytes * 2, 56 bytes * 2
|
||||||
|
this.session_key2 = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring(112, 144)); // 56 bytes * 2, 72 bytes * 2
|
||||||
|
|
||||||
|
const echo_encrypted = CryptoJS.DES.encrypt(
|
||||||
|
CryptoJS.MD5(challenge_echo).concat(challenge_echo).concat(CryptoJS.enc.Utf8.parse("\x08".repeat(8))),
|
||||||
|
this.current_shared_key,
|
||||||
|
{ mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }
|
||||||
|
);
|
||||||
|
|
||||||
|
this.challenge_raw = challenge_raw;
|
||||||
|
this.challenge_key = this.current_shared_key;
|
||||||
|
|
||||||
|
return CryptoJS.enc.Hex.parse(challenge_id_hex).concat(echo_encrypted.ciphertext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a wtv-challenge for this instance
|
* Generates a wtv-challenge for this instance
|
||||||
*
|
*
|
||||||
@@ -254,33 +247,32 @@ class WTVSec {
|
|||||||
* bytes 88 - 104: MD5 of 8 - 88
|
* bytes 88 - 104: MD5 of 8 - 88
|
||||||
* bytes 104 - 112: padding.not important
|
* bytes 104 - 112: padding.not important
|
||||||
*/
|
*/
|
||||||
|
const challenge_id = CryptoJS.lib.WordArray.random(8);
|
||||||
|
const echo_me = CryptoJS.lib.WordArray.random(40);
|
||||||
var challenge_id = CryptoJS.lib.WordArray.random(8);
|
|
||||||
|
|
||||||
var echo_me = CryptoJS.lib.WordArray.random(40);
|
|
||||||
this.session_key1 = CryptoJS.lib.WordArray.random(16);
|
this.session_key1 = CryptoJS.lib.WordArray.random(16);
|
||||||
this.session_key2 = CryptoJS.lib.WordArray.random(16);
|
this.session_key2 = CryptoJS.lib.WordArray.random(16);
|
||||||
var new_shared_key = CryptoJS.lib.WordArray.random(8);
|
const new_shared_key = CryptoJS.lib.WordArray.random(8);
|
||||||
|
|
||||||
var session_key1 = this.DuplicateWordArray(this.session_key1);
|
const challenge_puzzle = echo_me
|
||||||
var session_key2 = this.DuplicateWordArray(this.session_key2);
|
.concat(this.session_key1)
|
||||||
|
.concat(this.session_key2)
|
||||||
|
.concat(new_shared_key);
|
||||||
|
|
||||||
var challenge_puzzle = echo_me.concat(session_key1.concat(session_key2.concat(new_shared_key)));
|
const md5Hash = CryptoJS.MD5(challenge_puzzle);
|
||||||
var challenge_secret = challenge_puzzle.concat(CryptoJS.MD5(challenge_puzzle).concat(CryptoJS.enc.Hex.parse("\x08".repeat(8))));
|
const padding = CryptoJS.enc.Hex.parse("\x08".repeat(8));
|
||||||
|
const challenge_secret = challenge_puzzle.concat(md5Hash).concat(padding);
|
||||||
// Shhhh!!
|
|
||||||
var challenge_secreted = CryptoJS.DES.encrypt(challenge_secret, this.current_shared_key, {
|
const challenge_secreted = CryptoJS.DES.encrypt(challenge_secret, this.current_shared_key, {
|
||||||
mode: CryptoJS.mode.ECB,
|
mode: CryptoJS.mode.ECB,
|
||||||
padding: CryptoJS.pad.NoPadding
|
padding: CryptoJS.pad.NoPadding
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var challenge = challenge_id.concat(challenge_secreted.ciphertext);
|
const challenge = challenge_id.concat(challenge_secreted.ciphertext);
|
||||||
var challenge_b64 = challenge.toString(CryptoJS.enc.Base64);
|
const challenge_b64 = challenge.toString(CryptoJS.enc.Base64);
|
||||||
// get the expected response for when client sends it
|
|
||||||
this.challenge_signed_key = this.current_shared_key;
|
this.challenge_signed_key = this.current_shared_key;
|
||||||
this.challenge_response = this.ProcessChallenge(challenge_b64);
|
this.challenge_response = this.ProcessChallenge(challenge_b64);
|
||||||
|
|
||||||
return challenge_b64;
|
return challenge_b64;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,24 +301,22 @@ class WTVSec {
|
|||||||
this.hRC4_Key2 = CryptoJS.MD5(this.DuplicateWordArray(this.session_key2).concat(CryptoJS.lib.WordArray.create(buf).concat(this.DuplicateWordArray(this.session_key2))));
|
this.hRC4_Key2 = CryptoJS.MD5(this.DuplicateWordArray(this.session_key2).concat(CryptoJS.lib.WordArray.create(buf).concat(this.DuplicateWordArray(this.session_key2))));
|
||||||
var key1 = this.wordArrayToBuffer(this.hRC4_Key1);
|
var key1 = this.wordArrayToBuffer(this.hRC4_Key1);
|
||||||
var key2 = this.wordArrayToBuffer(this.hRC4_Key2);
|
var key2 = this.wordArrayToBuffer(this.hRC4_Key2);
|
||||||
|
const setRC4Session = (sessionIndex, key) => {
|
||||||
|
this.RC4Session[sessionIndex] = new RC4.RC4(key);
|
||||||
|
};
|
||||||
|
|
||||||
switch (rc4session) {
|
switch (rc4session) {
|
||||||
case 0:
|
case 0:
|
||||||
this.RC4Session[0] = new RC4.RC4(key1);
|
|
||||||
break;
|
|
||||||
case 1:
|
case 1:
|
||||||
this.RC4Session[1] = new RC4.RC4(key1);
|
setRC4Session(rc4session, key1);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
this.RC4Session[2] = new RC4.RC4(key2);
|
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
this.RC4Session[3] = new RC4.RC4(key2);
|
setRC4Session(rc4session, key2);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.RC4Session[0] = new RC4.RC4(key1);
|
[0, 1].forEach(index => setRC4Session(index, key1));
|
||||||
this.RC4Session[1] = new RC4.RC4(key1);
|
[2, 3].forEach(index => setRC4Session(index, key2));
|
||||||
this.RC4Session[2] = new RC4.RC4(key2);
|
|
||||||
this.RC4Session[3] = new RC4.RC4(key2);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,29 +329,29 @@ class WTVSec {
|
|||||||
* @returns {ArrayBuffer} Encrypted data
|
* @returns {ArrayBuffer} Encrypted data
|
||||||
*/
|
*/
|
||||||
Encrypt(keynum, data) {
|
Encrypt(keynum, data) {
|
||||||
var session_id;
|
let session_id;
|
||||||
switch (keynum) {
|
if (keynum === 0) {
|
||||||
case 0:
|
session_id = 0;
|
||||||
session_id = 0;
|
} else if (keynum === 1) {
|
||||||
break;
|
session_id = 2;
|
||||||
case 1:
|
} else {
|
||||||
session_id = 2
|
throw new Error("Invalid key option (0 or 1 only)");
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw ("Invalid key option (0 or 1 only)");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.RC4Session[session_id]) {
|
if (!this.RC4Session[session_id]) {
|
||||||
this.SecureOn(session_id);
|
this.SecureOn(session_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.words) {
|
if (data.words) {
|
||||||
data = this.wordArrayToBuffer(data);
|
data = this.wordArrayToBuffer(data);
|
||||||
} else if (data.constructor === ArrayBuffer || typeof data == 'string') {
|
} else if (data instanceof ArrayBuffer || typeof data === 'string') {
|
||||||
data = new Buffer.from(data);
|
data = Buffer.from(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.RC4Session[session_id].updateFromBuffer(data);
|
return this.RC4Session[session_id].updateFromBuffer(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RC4 Decrypt data
|
* RC4 Decrypt data
|
||||||
* @param {Number} keynum Which key to use (0 = k1, 1 = k2)
|
* @param {Number} keynum Which key to use (0 = k1, 1 = k2)
|
||||||
@@ -370,27 +360,7 @@ class WTVSec {
|
|||||||
* @returns {ArrayBuffer} Decrypted data
|
* @returns {ArrayBuffer} Decrypted data
|
||||||
*/
|
*/
|
||||||
Decrypt(keynum, data) {
|
Decrypt(keynum, data) {
|
||||||
var session_id;
|
return this.Encrypt(keynum, data)
|
||||||
switch (keynum) {
|
|
||||||
case 0:
|
|
||||||
session_id = 1;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
session_id = 3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw ("Invalid key option (0 or 1 only)");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!this.RC4Session[session_id]) {
|
|
||||||
this.SecureOn(session_id);
|
|
||||||
}
|
|
||||||
if (data.words) {
|
|
||||||
data = this.wordArrayToBuffer(data);
|
|
||||||
} else if (data.constructor === ArrayBuffer || typeof data == 'string') {
|
|
||||||
data = new Buffer.from(data);
|
|
||||||
}
|
|
||||||
return this.RC4Session[session_id].updateFromBuffer(data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,25 +53,23 @@ class WTVShared {
|
|||||||
*/
|
*/
|
||||||
getSSIDCRC(ssid) {
|
getSSIDCRC(ssid) {
|
||||||
let crc = 0;
|
let crc = 0;
|
||||||
var ssid = ssid.substr(0, 14);
|
|
||||||
|
|
||||||
for (let i = 0; i < ssid.length; i += 2) {
|
for (let i = 0; i < 14; i += 2) {
|
||||||
let inbyte = parseInt(ssid.substring(i, i + 2), 16);
|
let inbyte = parseInt(ssid.substring(i, i + 2), 16);
|
||||||
for (let ii = 8; ii > 0; ii--) {
|
if (isNaN(inbyte)) return '00';
|
||||||
let mix = (crc ^ inbyte) & 0x01;
|
|
||||||
|
for (let ii = 0; ii < 8; ii++) {
|
||||||
|
let mix = (crc ^ inbyte) & 1;
|
||||||
crc >>= 1;
|
crc >>= 1;
|
||||||
if (mix != 0) crc ^= 0x8C;
|
if (mix) crc ^= 0x8C;
|
||||||
inbyte >>= 1;
|
inbyte >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNaN(crc)) crc = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var out = crc.toString(16);
|
return crc.toString(16).padStart(2, '0');
|
||||||
if (out.length == 1) return "0" + out;
|
|
||||||
else return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
parseConfigVars(s) {
|
parseConfigVars(s) {
|
||||||
if (s.indexOf("%ServiceDeps%") >= 0) {
|
if (s.indexOf("%ServiceDeps%") >= 0) {
|
||||||
return this.getServiceDep(s.replace("%ServiceDeps%", ""), true);
|
return this.getServiceDep(s.replace("%ServiceDeps%", ""), true);
|
||||||
@@ -112,20 +110,19 @@ class WTVShared {
|
|||||||
return new RegExp(src);
|
return new RegExp(src);
|
||||||
} else if (src instanceof Date) {
|
} else if (src instanceof Date) {
|
||||||
return new Date(src.getTime());
|
return new Date(src.getTime());
|
||||||
|
} else if (Array.isArray(src)) {
|
||||||
|
return src.map(item => this.cloneObj(item));
|
||||||
} else if (typeof src === 'object' && src !== null) {
|
} else if (typeof src === 'object' && src !== null) {
|
||||||
var clone = null;
|
const clone = {};
|
||||||
if (Array.isArray(src)) clone = [];
|
Object.keys(src).forEach(k => {
|
||||||
else clone = {};
|
clone[k] = this.cloneObj(src[k]);
|
||||||
|
|
||||||
var self = this;
|
|
||||||
Object.keys(src).forEach((k )=> {
|
|
||||||
clone[k] = self.cloneObj(src[k]);
|
|
||||||
});
|
});
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the user has been whitelisted for wtv-admin
|
* Checks if the user has been whitelisted for wtv-admin
|
||||||
* @param {object} wtvclient the clientSessionData object for the user
|
* @param {object} wtvclient the clientSessionData object for the user
|
||||||
|
|||||||
Reference in New Issue
Block a user