From c0d54b851354842d6649b04ae6b3f7cb5f037288 Mon Sep 17 00:00:00 2001 From: echo Date: Wed, 5 Nov 2025 17:25:23 +0800 Subject: [PATCH] feat: update --- src/utils/network/des.ts | 492 ++++++++++++++++++++++++++++++++++++ src/utils/network/error.ts | 119 +++++++++ src/utils/network/helper.ts | 421 ++++++++++++++++++++++++++++++ 3 files changed, 1032 insertions(+) create mode 100644 src/utils/network/des.ts create mode 100644 src/utils/network/error.ts create mode 100644 src/utils/network/helper.ts diff --git a/src/utils/network/des.ts b/src/utils/network/des.ts new file mode 100644 index 0000000..0076a40 --- /dev/null +++ b/src/utils/network/des.ts @@ -0,0 +1,492 @@ +// @ts-nocheck +//des +//this takes the key, the message, and whether to encrypt or decrypt + +export function des(key, message, encrypt, mode, iv, padding) { + if (encrypt) + //如果是加密的话,首先转换编码 + message = unescape(encodeURIComponent(message)); + //declaring this locally speeds things up a bit + const spfunction1 = [ + 0x1010400, 0, 0x10000, 0x1010404, 0x1010004, 0x10404, 0x4, 0x10000, 0x400, 0x1010400, 0x1010404, + 0x400, 0x1000404, 0x1010004, 0x1000000, 0x4, 0x404, 0x1000400, 0x1000400, 0x10400, 0x10400, + 0x1010000, 0x1010000, 0x1000404, 0x10004, 0x1000004, 0x1000004, 0x10004, 0, 0x404, 0x10404, + 0x1000000, 0x10000, 0x1010404, 0x4, 0x1010000, 0x1010400, 0x1000000, 0x1000000, 0x400, + 0x1010004, 0x10000, 0x10400, 0x1000004, 0x400, 0x4, 0x1000404, 0x10404, 0x1010404, 0x10004, + 0x1010000, 0x1000404, 0x1000004, 0x404, 0x10404, 0x1010400, 0x404, 0x1000400, 0x1000400, 0, + 0x10004, 0x10400, 0, 0x1010004, + ]; + const spfunction2 = [ + -0x7fef7fe0, -0x7fff8000, 0x8000, 0x108020, 0x100000, 0x20, -0x7fefffe0, -0x7fff7fe0, + -0x7fffffe0, -0x7fef7fe0, -0x7fef8000, -0x80000000, -0x7fff8000, 0x100000, 0x20, -0x7fefffe0, + 0x108000, 0x100020, -0x7fff7fe0, 0, -0x80000000, 0x8000, 0x108020, -0x7ff00000, 0x100020, + -0x7fffffe0, 0, 0x108000, 0x8020, -0x7fef8000, -0x7ff00000, 0x8020, 0, 0x108020, -0x7fefffe0, + 0x100000, -0x7fff7fe0, -0x7ff00000, -0x7fef8000, 0x8000, -0x7ff00000, -0x7fff8000, 0x20, + -0x7fef7fe0, 0x108020, 0x20, 0x8000, -0x80000000, 0x8020, -0x7fef8000, 0x100000, -0x7fffffe0, + 0x100020, -0x7fff7fe0, -0x7fffffe0, 0x100020, 0x108000, 0, -0x7fff8000, 0x8020, -0x80000000, + -0x7fefffe0, -0x7fef7fe0, 0x108000, + ]; + const spfunction3 = [ + 0x208, 0x8020200, 0, 0x8020008, 0x8000200, 0, 0x20208, 0x8000200, 0x20008, 0x8000008, 0x8000008, + 0x20000, 0x8020208, 0x20008, 0x8020000, 0x208, 0x8000000, 0x8, 0x8020200, 0x200, 0x20200, + 0x8020000, 0x8020008, 0x20208, 0x8000208, 0x20200, 0x20000, 0x8000208, 0x8, 0x8020208, 0x200, + 0x8000000, 0x8020200, 0x8000000, 0x20008, 0x208, 0x20000, 0x8020200, 0x8000200, 0, 0x200, + 0x20008, 0x8020208, 0x8000200, 0x8000008, 0x200, 0, 0x8020008, 0x8000208, 0x20000, 0x8000000, + 0x8020208, 0x8, 0x20208, 0x20200, 0x8000008, 0x8020000, 0x8000208, 0x208, 0x8020000, 0x20208, + 0x8, 0x8020008, 0x20200, + ]; + const spfunction4 = [ + 0x802001, 0x2081, 0x2081, 0x80, 0x802080, 0x800081, 0x800001, 0x2001, 0, 0x802000, 0x802000, + 0x802081, 0x81, 0, 0x800080, 0x800001, 0x1, 0x2000, 0x800000, 0x802001, 0x80, 0x800000, 0x2001, + 0x2080, 0x800081, 0x1, 0x2080, 0x800080, 0x2000, 0x802080, 0x802081, 0x81, 0x800080, 0x800001, + 0x802000, 0x802081, 0x81, 0, 0, 0x802000, 0x2080, 0x800080, 0x800081, 0x1, 0x802001, 0x2081, + 0x2081, 0x80, 0x802081, 0x81, 0x1, 0x2000, 0x800001, 0x2001, 0x802080, 0x800081, 0x2001, 0x2080, + 0x800000, 0x802001, 0x80, 0x800000, 0x2000, 0x802080, + ]; + const spfunction5 = [ + 0x100, 0x2080100, 0x2080000, 0x42000100, 0x80000, 0x100, 0x40000000, 0x2080000, 0x40080100, + 0x80000, 0x2000100, 0x40080100, 0x42000100, 0x42080000, 0x80100, 0x40000000, 0x2000000, + 0x40080000, 0x40080000, 0, 0x40000100, 0x42080100, 0x42080100, 0x2000100, 0x42080000, + 0x40000100, 0, 0x42000000, 0x2080100, 0x2000000, 0x42000000, 0x80100, 0x80000, 0x42000100, + 0x100, 0x2000000, 0x40000000, 0x2080000, 0x42000100, 0x40080100, 0x2000100, 0x40000000, + 0x42080000, 0x2080100, 0x40080100, 0x100, 0x2000000, 0x42080000, 0x42080100, 0x80100, + 0x42000000, 0x42080100, 0x2080000, 0, 0x40080000, 0x42000000, 0x80100, 0x2000100, 0x40000100, + 0x80000, 0, 0x40080000, 0x2080100, 0x40000100, + ]; + const spfunction6 = [ + 0x20000010, 0x20400000, 0x4000, 0x20404010, 0x20400000, 0x10, 0x20404010, 0x400000, 0x20004000, + 0x404010, 0x400000, 0x20000010, 0x400010, 0x20004000, 0x20000000, 0x4010, 0, 0x400010, + 0x20004010, 0x4000, 0x404000, 0x20004010, 0x10, 0x20400010, 0x20400010, 0, 0x404010, 0x20404000, + 0x4010, 0x404000, 0x20404000, 0x20000000, 0x20004000, 0x10, 0x20400010, 0x404000, 0x20404010, + 0x400000, 0x4010, 0x20000010, 0x400000, 0x20004000, 0x20000000, 0x4010, 0x20000010, 0x20404010, + 0x404000, 0x20400000, 0x404010, 0x20404000, 0, 0x20400010, 0x10, 0x4000, 0x20400000, 0x404010, + 0x4000, 0x400010, 0x20004010, 0, 0x20404000, 0x20000000, 0x400010, 0x20004010, + ]; + const spfunction7 = [ + 0x200000, 0x4200002, 0x4000802, 0, 0x800, 0x4000802, 0x200802, 0x4200800, 0x4200802, 0x200000, + 0, 0x4000002, 0x2, 0x4000000, 0x4200002, 0x802, 0x4000800, 0x200802, 0x200002, 0x4000800, + 0x4000002, 0x4200000, 0x4200800, 0x200002, 0x4200000, 0x800, 0x802, 0x4200802, 0x200800, 0x2, + 0x4000000, 0x200800, 0x4000000, 0x200800, 0x200000, 0x4000802, 0x4000802, 0x4200002, 0x4200002, + 0x2, 0x200002, 0x4000000, 0x4000800, 0x200000, 0x4200800, 0x802, 0x200802, 0x4200800, 0x802, + 0x4000002, 0x4200802, 0x4200000, 0x200800, 0, 0x2, 0x4200802, 0, 0x200802, 0x4200000, 0x800, + 0x4000002, 0x4000800, 0x800, 0x200002, + ]; + const spfunction8 = [ + 0x10001040, 0x1000, 0x40000, 0x10041040, 0x10000000, 0x10001040, 0x40, 0x10000000, 0x40040, + 0x10040000, 0x10041040, 0x41000, 0x10041000, 0x41040, 0x1000, 0x40, 0x10040000, 0x10000040, + 0x10001000, 0x1040, 0x41000, 0x40040, 0x10040040, 0x10041000, 0x1040, 0, 0, 0x10040040, + 0x10000040, 0x10001000, 0x41040, 0x40000, 0x41040, 0x40000, 0x10041000, 0x1000, 0x40, + 0x10040040, 0x1000, 0x41040, 0x10001000, 0x40, 0x10000040, 0x10040000, 0x10040040, 0x10000000, + 0x40000, 0x10001040, 0, 0x10041040, 0x40040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0, + 0x10041040, 0x41000, 0x41000, 0x1040, 0x1040, 0x40040, 0x10000000, 0x10041000, + ]; + + //create the 16 or 48 subkeys we will need + const keys = des_createKeys(key); + let m = 0, + i, + j, + temp, + temp2, + right1, + right2, + left, + right, + looping; + let cbcleft, cbcleft2, cbcright, cbcright2; + let endloop, loopinc; + var len = message.length; + let chunk = 0; + //set up the loops for single and triple des + const iterations = keys.length == 32 ? 3 : 9; //single or triple des + if (iterations == 3) { + looping = encrypt ? [0, 32, 2] : [30, -2, -2]; + } else { + looping = encrypt ? [0, 32, 2, 62, 30, -2, 64, 96, 2] : [94, 62, -2, 32, 64, 2, 30, -2, -2]; + } + + //pad the message depending on the padding parameter + if (padding == 2) + message += ' '; //pad the message with spaces + else if (padding == 1) { + if (encrypt) { + temp = 8 - (len % 8); + message += String.fromCharCode(temp, temp, temp, temp, temp, temp, temp, temp); + if (temp === 8) len += 8; + } + } //PKCS7 padding + else if (!padding) message += '\0\0\0\0\0\0\0\0'; //pad the message out with null bytes + + //store the result here + let result = ''; + let tempresult = ''; + + if (mode == 1) { + //CBC mode + cbcleft = + (iv.charCodeAt(m++) << 24) | + (iv.charCodeAt(m++) << 16) | + (iv.charCodeAt(m++) << 8) | + iv.charCodeAt(m++); + cbcright = + (iv.charCodeAt(m++) << 24) | + (iv.charCodeAt(m++) << 16) | + (iv.charCodeAt(m++) << 8) | + iv.charCodeAt(m++); + m = 0; + } + + //loop through each 64 bit chunk of the message + while (m < len) { + left = + (message.charCodeAt(m++) << 24) | + (message.charCodeAt(m++) << 16) | + (message.charCodeAt(m++) << 8) | + message.charCodeAt(m++); + right = + (message.charCodeAt(m++) << 24) | + (message.charCodeAt(m++) << 16) | + (message.charCodeAt(m++) << 8) | + message.charCodeAt(m++); + + //for Cipher Block Chaining mode, xor the message with the previous result + if (mode == 1) { + if (encrypt) { + left ^= cbcleft; + right ^= cbcright; + } else { + cbcleft2 = cbcleft; + cbcright2 = cbcright; + cbcleft = left; + cbcright = right; + } + } + + //first each 64 but chunk of the message must be permuted according to IP + temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= temp; + left ^= temp << 4; + temp = ((left >>> 16) ^ right) & 0x0000ffff; + right ^= temp; + left ^= temp << 16; + temp = ((right >>> 2) ^ left) & 0x33333333; + left ^= temp; + right ^= temp << 2; + temp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= temp; + right ^= temp << 8; + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= temp << 1; + + left = (left << 1) | (left >>> 31); + right = (right << 1) | (right >>> 31); + + //do this either 1 or 3 times for each chunk of the message + for (j = 0; j < iterations; j += 3) { + endloop = looping[j + 1]; + loopinc = looping[j + 2]; + //now go through and perform the encryption or decryption + for (i = looping[j]; i != endloop; i += loopinc) { + //for efficiency + right1 = right ^ keys[i]; + right2 = ((right >>> 4) | (right << 28)) ^ keys[i + 1]; + //the result is attained by passing these bytes through the S selection functions + temp = left; + left = right; + right = + temp ^ + (spfunction2[(right1 >>> 24) & 0x3f] | + spfunction4[(right1 >>> 16) & 0x3f] | + spfunction6[(right1 >>> 8) & 0x3f] | + spfunction8[right1 & 0x3f] | + spfunction1[(right2 >>> 24) & 0x3f] | + spfunction3[(right2 >>> 16) & 0x3f] | + spfunction5[(right2 >>> 8) & 0x3f] | + spfunction7[right2 & 0x3f]); + } + temp = left; + left = right; + right = temp; //unreverse left and right + } //for either 1 or 3 iterations + + //move then each one bit to the right + left = (left >>> 1) | (left << 31); + right = (right >>> 1) | (right << 31); + + //now perform IP-1, which is IP in the opposite direction + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= temp << 1; + temp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= temp; + right ^= temp << 8; + temp = ((right >>> 2) ^ left) & 0x33333333; + left ^= temp; + right ^= temp << 2; + temp = ((left >>> 16) ^ right) & 0x0000ffff; + right ^= temp; + left ^= temp << 16; + temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= temp; + left ^= temp << 4; + + //for Cipher Block Chaining mode, xor the message with the previous result + if (mode == 1) { + if (encrypt) { + cbcleft = left; + cbcright = right; + } else { + left ^= cbcleft2; + right ^= cbcright2; + } + } + tempresult += String.fromCharCode( + left >>> 24, + (left >>> 16) & 0xff, + (left >>> 8) & 0xff, + left & 0xff, + right >>> 24, + (right >>> 16) & 0xff, + (right >>> 8) & 0xff, + right & 0xff + ); + + chunk += 8; + if (chunk == 512) { + result += tempresult; + tempresult = ''; + chunk = 0; + } + } //for every 8 characters, or 64 bits in the message + + //return the result as an array + result += tempresult; + if (!encrypt) result = result.replace(/\0*$/g, ''); + + if (!encrypt) { + //如果是解密的话,解密结束后对PKCS7 padding进行解码,并转换成utf-8编码 + if (padding === 1) { + //PKCS7 padding解码 + var len = result.length, + paddingChars = 0; + len && (paddingChars = result.charCodeAt(len - 1)); + paddingChars <= 8 && (result = result.substring(0, len - paddingChars)); + } + //转换成UTF-8编码 + result = decodeURIComponent(escape(result)); + } + + return result; +} //end of des + +//des_createKeys +//this takes as input a 64 bit key (even though only 56 bits are used) +//as an array of 2 integers, and returns 16 48 bit keys +function des_createKeys(key) { + //declaring this locally speeds things up a bit + const pc2bytes0 = [ + 0, 0x4, 0x20000000, 0x20000004, 0x10000, 0x10004, 0x20010000, 0x20010004, 0x200, 0x204, + 0x20000200, 0x20000204, 0x10200, 0x10204, 0x20010200, 0x20010204, + ]; + const pc2bytes1 = [ + 0, 0x1, 0x100000, 0x100001, 0x4000000, 0x4000001, 0x4100000, 0x4100001, 0x100, 0x101, 0x100100, + 0x100101, 0x4000100, 0x4000101, 0x4100100, 0x4100101, + ]; + const pc2bytes2 = [ + 0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808, 0, 0x8, 0x800, 0x808, + 0x1000000, 0x1000008, 0x1000800, 0x1000808, + ]; + const pc2bytes3 = [ + 0, 0x200000, 0x8000000, 0x8200000, 0x2000, 0x202000, 0x8002000, 0x8202000, 0x20000, 0x220000, + 0x8020000, 0x8220000, 0x22000, 0x222000, 0x8022000, 0x8222000, + ]; + const pc2bytes4 = [ + 0, 0x40000, 0x10, 0x40010, 0, 0x40000, 0x10, 0x40010, 0x1000, 0x41000, 0x1010, 0x41010, 0x1000, + 0x41000, 0x1010, 0x41010, + ]; + const pc2bytes5 = [ + 0, 0x400, 0x20, 0x420, 0, 0x400, 0x20, 0x420, 0x2000000, 0x2000400, 0x2000020, 0x2000420, + 0x2000000, 0x2000400, 0x2000020, 0x2000420, + ]; + const pc2bytes6 = [ + 0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002, 0, 0x10000000, + 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002, + ]; + const pc2bytes7 = [ + 0, 0x10000, 0x800, 0x10800, 0x20000000, 0x20010000, 0x20000800, 0x20010800, 0x20000, 0x30000, + 0x20800, 0x30800, 0x20020000, 0x20030000, 0x20020800, 0x20030800, + ]; + const pc2bytes8 = [ + 0, 0x40000, 0, 0x40000, 0x2, 0x40002, 0x2, 0x40002, 0x2000000, 0x2040000, 0x2000000, 0x2040000, + 0x2000002, 0x2040002, 0x2000002, 0x2040002, + ]; + const pc2bytes9 = [ + 0, 0x10000000, 0x8, 0x10000008, 0, 0x10000000, 0x8, 0x10000008, 0x400, 0x10000400, 0x408, + 0x10000408, 0x400, 0x10000400, 0x408, 0x10000408, + ]; + const pc2bytes10 = [ + 0, 0x20, 0, 0x20, 0x100000, 0x100020, 0x100000, 0x100020, 0x2000, 0x2020, 0x2000, 0x2020, + 0x102000, 0x102020, 0x102000, 0x102020, + ]; + const pc2bytes11 = [ + 0, 0x1000000, 0x200, 0x1000200, 0x200000, 0x1200000, 0x200200, 0x1200200, 0x4000000, 0x5000000, + 0x4000200, 0x5000200, 0x4200000, 0x5200000, 0x4200200, 0x5200200, + ]; + const pc2bytes12 = [ + 0, 0x1000, 0x8000000, 0x8001000, 0x80000, 0x81000, 0x8080000, 0x8081000, 0x10, 0x1010, + 0x8000010, 0x8001010, 0x80010, 0x81010, 0x8080010, 0x8081010, + ]; + const pc2bytes13 = [ + 0, 0x4, 0x100, 0x104, 0, 0x4, 0x100, 0x104, 0x1, 0x5, 0x101, 0x105, 0x1, 0x5, 0x101, 0x105, + ]; + + //how many iterations (1 for des, 3 for triple des) + const iterations = key.length > 8 ? 3 : 1; //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys + //stores the return keys + const keys = new Array(32 * iterations); + //now define the left shifts which need to be done + const shifts = [0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0]; + //other variables + let lefttemp, + righttemp, + m = 0, + n = 0, + temp; + + for (let j = 0; j < iterations; j++) { + //either 1 or 3 iterations + let left = + (key.charCodeAt(m++) << 24) | + (key.charCodeAt(m++) << 16) | + (key.charCodeAt(m++) << 8) | + key.charCodeAt(m++); + let right = + (key.charCodeAt(m++) << 24) | + (key.charCodeAt(m++) << 16) | + (key.charCodeAt(m++) << 8) | + key.charCodeAt(m++); + + temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= temp; + left ^= temp << 4; + temp = ((right >>> -16) ^ left) & 0x0000ffff; + left ^= temp; + right ^= temp << -16; + temp = ((left >>> 2) ^ right) & 0x33333333; + right ^= temp; + left ^= temp << 2; + temp = ((right >>> -16) ^ left) & 0x0000ffff; + left ^= temp; + right ^= temp << -16; + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= temp << 1; + temp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= temp; + right ^= temp << 8; + temp = ((left >>> 1) ^ right) & 0x55555555; + right ^= temp; + left ^= temp << 1; + + //the right side needs to be shifted and to get the last four bits of the left side + temp = (left << 8) | ((right >>> 20) & 0x000000f0); + //left needs to be put upside down + left = + (right << 24) | + ((right << 8) & 0xff0000) | + ((right >>> 8) & 0xff00) | + ((right >>> 24) & 0xf0); + right = temp; + + //now go through and perform these shifts on the left and right keys + for (let i = 0; i < shifts.length; i++) { + //shift the keys either one or two bits to the left + if (shifts[i]) { + left = (left << 2) | (left >>> 26); + right = (right << 2) | (right >>> 26); + } else { + left = (left << 1) | (left >>> 27); + right = (right << 1) | (right >>> 27); + } + left &= -0xf; + right &= -0xf; + + //now apply PC-2, in such a way that E is easier when encrypting or decrypting + //this conversion will look like PC-2 except only the last 6 bits of each byte are used + //rather than 48 consecutive bits and the order of lines will be according to + //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7 + lefttemp = + pc2bytes0[left >>> 28] | + pc2bytes1[(left >>> 24) & 0xf] | + pc2bytes2[(left >>> 20) & 0xf] | + pc2bytes3[(left >>> 16) & 0xf] | + pc2bytes4[(left >>> 12) & 0xf] | + pc2bytes5[(left >>> 8) & 0xf] | + pc2bytes6[(left >>> 4) & 0xf]; + righttemp = + pc2bytes7[right >>> 28] | + pc2bytes8[(right >>> 24) & 0xf] | + pc2bytes9[(right >>> 20) & 0xf] | + pc2bytes10[(right >>> 16) & 0xf] | + pc2bytes11[(right >>> 12) & 0xf] | + pc2bytes12[(right >>> 8) & 0xf] | + pc2bytes13[(right >>> 4) & 0xf]; + temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff; + keys[n++] = lefttemp ^ temp; + keys[n++] = righttemp ^ (temp << 16); + } + } //for each iterations + //return the keys we've created + return keys; +} //end of des_createKeys +function genkey(key, start, end) { + //8 byte / 64 bit Key (DES) or 192 bit Key + return { key: pad(key.slice(start, end)), vector: 1 }; +} + +function pad(key) { + for (let i = key.length; i < 24; i++) { + key += '0'; + } + return key; +} +//3DES加密,使用PKCS7 padding +function encrypt_3des(key, input) { + const genKey = genkey(key, 0, 24); + return btoa(des(genKey.key, input, 1, 0, 0, 1)); +} +//3DES解密,使用PKCS7 padding +function decrypt_3des(key, input) { + const genKey = genkey(key, 0, 24); + return des(genKey.key, atob(input), 0, 0, 0, 1); +} + +////////////////////////////// TEST ////////////////////////////// +export function stringToHex(s) { + let r = '0x'; + const hexes = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; + for (let i = 0; i < s.length; i++) { + r += hexes[s.charCodeAt(i) >> 4] + hexes[s.charCodeAt(i) & 0xf]; + } + return r; +} + +export function stringToHexArray(s) { + const arr = []; + const hexes = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; + for (let i = 0; i < s.length; i++) { + arr.push(hexes[s.charCodeAt(i) >> 4] + hexes[s.charCodeAt(i) & 0xf]); + } + return arr; +} + +export function hexToString(h) { + let r = ''; + for (let i = h.substr(0, 2) == '0x' ? 2 : 0; i < h.length; i += 2) { + r += String.fromCharCode(parseInt(h.substr(i, 2), 16)); + } + return r; +} + +/* eslint-enable */ diff --git a/src/utils/network/error.ts b/src/utils/network/error.ts new file mode 100644 index 0000000..05b606e --- /dev/null +++ b/src/utils/network/error.ts @@ -0,0 +1,119 @@ +// import { useTenantStore, useUserStore, useModalStore } from '@star/stores'; +// import { mb_t } from '@star/languages'; +// import { router } from '@routers'; +import { endsWith, includes, startsWith } from 'lodash-es'; +// import { ModalTypeEnum } from '@star/constants'; + +// 错误提示 +export default class NetworkError { + tag: string; + key: string; + info: string; + level: string; + origin: string; + cmd: string; + code: number; + logout: boolean; + update: boolean; + time: string; + + constructor(options: any) { + this.tag = ''; + this.key = ''; + this.info = ''; + this.level = ''; + this.origin = ''; + this.cmd = ''; + // this.code = 0 + this.code = -1; + this.logout = false; + this.update = false; + this.time = new Date().toLocaleString().split('GMT')[0]; + if (options) { + if (options.key) { + this.key = options.key; + } + if (options.tag) { + this.tag = options.tag; + } + if (options.info) { + if (startsWith(options.info, '{') && endsWith(options.info, '}')) { + const result = JSON.parse(options.info); + this.info = result?.msg || result?.exMessage || ''; + } else { + this.info = options.info; + } + } + if (options.level) { + this.level = options.level; + } + if (options.origin) { + this.origin = options.origin; + } + if (options.cmd) { + this.cmd = options.cmd; + } + if (options.code) { + this.code = options.code; + } + if (options.logout) { + this.logout = options.logout; + } + if (options.update) { + this.update = options.update; + } + } + // const tenantStore = useTenantStore(); + // if ([371130, 381119].includes(Number(this.cmd))) { + // tenantStore.setRepairStatus(true); + // } + if (this.info.indexOf('invalid_token') !== -1) { + this.info = '亲,麻烦重新登录哦'; + } else if (this.info.indexOf('Request failed with status code 500') !== -1) { + this.info = '网络不给力,请检查网络' + '(500)'; + } else if (this.info.indexOf('Request failed with status code 502') !== -1) { + this.info = '网络不给力,请检查网络' + '(502)'; + } else if (this.info.indexOf('Error 503 Service Unavailable') !== -1) { + this.info = '网络不给力,请检查网络' + '(503)'; + } else if (this.info.indexOf('Request failed with status code 504') !== -1) { + this.info = '网络不给力,请检查网络' + '(504)'; + } else if (this.info.indexOf('timeout of 20000ms') !== -1) { + this.info = '请求超时,请检查网络'; + } else if (this.info.indexOf('Error 400 Bad Request') !== -1) { + this.info = '网络不给力,请重新尝试'; + } else if (this.info.indexOf('Network Error') !== -1) { + this.info = '网络错误,请检查网络'; + } else if (options?.code === '1115') { + // tenantStore.setRepairData(options.origin); + // tenantStore.setRepairStatus(true); + } else { + console.error('err.info:', this.cmd, this.info, options); + // this.info = this.info + // if (this.info) { + // showFailToast(mb_t(this.info)); + // } + // if (this.info && this.info.includes('重新登录')) { + // const userStore = useUserStore(); + // userStore?.clearUserInfo?.(); + // if ( + // !startsWith(router.currentRoute.value?.path, '/activity') && + // !includes(['home', 'mine', 'activity'], router.currentRoute.value?.name) + // ) { + // const modalStore = useModalStore(); + // const path = router.currentRoute.value?.fullPath; + // modalStore.showRegisterModal({ redirect: path }); + // router.replace?.('/home'); + // } + // } + // if (this.info.includes('访问限制')) { + // tenantStore.setIPLimitStatus(true); + // } + // [371130, 370433]返回了请求没有任何数据 才跳维护 其他接口忽略 + // if ([371130, 370433].includes(Number(this.cmd))) { + // // console.log(371130, 370433, this.info, '????????????????????????????'); + // tenantStore.setRepairStatus(true); + // } + } + // this.info = mb_t(this.info); + } +} diff --git a/src/utils/network/helper.ts b/src/utils/network/helper.ts new file mode 100644 index 0000000..ff39626 --- /dev/null +++ b/src/utils/network/helper.ts @@ -0,0 +1,421 @@ +import { HmacMD5 } from 'crypto-js'; +import Base64 from 'crypto-js/enc-base64'; +import Latin1 from 'crypto-js/enc-latin1'; +import md5 from 'md5'; +import { AxiosResponse } from 'axios'; +import * as des from './des'; +import NetworkError from './error'; +import { toNumber, toString, startsWith, isString, isNumber } from 'lodash-es'; +import { NetworkTypeEnum } from '@/constants/network'; +import config from '../config'; + +// import NetworkError from './error' +// import { storeToRefs, useTenantStore, useUserStore, useAppStore, start } from '../index'; +// import { isMobile, getBetPlatform } from '@star/utils'; +// import { langToNum } from '@star/languages'; + +// 请求到的数据返回 +export type NetworkResponse = { + type: NetworkTypeEnum; + data: T; +}; + +export const getBetPlatform = (isReturnIndex = false) => { + // 5=PC; 7=HOMESCREEN_IOS; 6=HOMESCREEN_ANDROID; 4=H5_IOS 3=IOS 2=H5_ANDROID; 1=ANDROID 8=马甲包 + return 'H5_IOS'; + // const platform = new URLSearchParams(window.location.search).get('platform'); + // if (platform) { + // return platform?.includes('IOS') ? 'IOS' : platform?.includes('ANDROID') ? 'ANDROID' : ''; + // } + // if (isAppMJB()) { + // return 'APPS_ANDROID'; + // } + // if (isPWA()) { + // if (isIOS()) { + // return isReturnIndex ? 4 : 'HS_IOS'; + // } else { + // return isReturnIndex ? 2 : 'HS_ANDROID'; + // } + // } + // if (isAndroid()) { + // if (BASE_CONFIG.appVersion > 0) { + // return isReturnIndex ? 1 : 'ANDROID'; + // } else { + // return isReturnIndex ? 2 : 'H5_ANDROID'; + // } + // } + // if (isIOS()) { + // if (BASE_CONFIG.appVersion > 0) { + // return isReturnIndex ? 3 : 'IOS'; + // } else { + // return isReturnIndex ? 4 : 'H5_IOS'; + // } + // } + // return isReturnIndex ? 5 : 'PC'; +}; + +const uuid = (len: number, radix: number) => { + const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); + const uuid: any[] = []; + radix = radix || chars.length; + + if (len) { + // Compact form + for (let i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)]; + } else { + // rfc4122, version 4 form + /* eslint-disable */ + let r; + + // rfc4122 requires these characters + uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; + uuid[14] = '4'; + + // Fill in random data. At i==19 set the high bits of clock sequence as + // per rfc4122, sec. 4.1.5 + for (let i = 0; i < 36; i++) { + if (!uuid[i]) { + r = 0 | (Math.random() * 16); + uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r]; + } + } + /* eslint-enable */ + } + return uuid.join(''); +}; + +// 格式化要发送的数据 +export const formatSendData = (data: any, type: number = 0) => { + // url code + if (type === 0) { + const arr: any[] = []; + for (const k in data) { + const v = data[k]; + if (v instanceof Array) { + for (const subK in v) { + arr.push(`${k}[]=${v[subK]}`); + } + } else { + arr.push(`${k}=${data[k]}`); + } + } + return arr.join('&'); + } else if (type === 2) { + return data.join('/'); + } + // json + return JSON.stringify(data); +}; + +export const getP = (p) => { + return HmacMD5(p, '7NEkojNzfkk=').toString(); +}; + +export const enD = (rk, str) => { + const enc = des.des(rk, str, 1, 0, null, 1); + return Base64.stringify(Latin1.parse(enc)); +}; + +export const dnD = (rk, str) => { + const s = Latin1.stringify(Base64.parse(str)); + const d = des.des(rk, s, 0, 0, null, 1); + return d; +}; + +export const enP = (rk, vk, t) => { + const enc = des.des(vk, rk + t, 1, 0, null, 1); + return Base64.stringify(Latin1.parse(enc)); +}; + +export const dnP = (vk, str) => { + const s = Latin1.stringify(Base64.parse(str)); + const p = des.des(vk, s, 0, 0, null, 1); + return p; +}; + +export const enC = (rk, vk, m) => { + const enc = HmacMD5(m + rk, vk); + return Base64.stringify(enc); +}; + +export const getRequestKey = (cmdId: number, data: any) => { + return `${cmdId}&${data ? md5(JSON.stringify(data)) : ''}`; +}; + +// 加工请求数据 +export const transformRequest = (config: any) => { + const { headerType = 2, paramType = 0, cmdId, tid, ...reset } = config.headers; + const headers: Record = {}; + // const { tenantInfo } = storeToRefs(useTenantStore()); + // const { userInfo } = storeToRefs(useUserStore()); + // const { language } = storeToRefs(useAppStore()); + const t = new Date().getTime(); + const rk = md5(toString(Math.random() + t)).substring(0, 8); + const vk = config.app.vk; + const pwds = enP(rk, vk, t); + + const tenantInfo = { + tid: 3, + }; + let userInfo = { + cust_id: 1, + cust_name: 'test', + }; + + // if (['17', '3310052', '310111', '310122', '310400', '4', '402', '401', '310635'].includes(cmdId)) { + // const publicParams = { + // tid: tid ?? tenantInfo.value?.tid ?? '', + // cust_id: (config.data?.cust_id === 0 ? '0' : '') || userInfo?.value?.cust_id || '', + // cust_name: (config.data?.cust_name === 0 ? '0' : config.data?.cust_name) || userInfo?.value?.cust_name || '', + // oper_code: (config.data?.cust_id === 0 ? '0' : '') || userInfo?.value?.cust_id || '', + // oper_name: (config.data?.cust_name === 0 ? '0' : config.data?.cust_name) || userInfo?.value?.cust_name || '', + // }; + // const localData = localStorage.getItem('publicData') || ''; + // const publicData = localData ? JSON.parse(localData) : {}; + // if (['17', '3310052', '310111', '310122'].includes(cmdId)) { + // if (['4', '402', '401'].includes(cmdId)) { + // publicParams.tid = publicParams?.tid.toString(); + // publicData.client_type = publicData?.client_type.toString(); + // publicData.oper_class_type = publicData?.oper_class_type.toString(); + // publicData.oper_source_type = publicData?.oper_source_type.toString(); + // publicData.mark = publicData?.mark.toString(); + // // publicData.ori_value = ""; + // // publicData.new_value = ""; + // // publicData.trans_type = "101"; + // // publicData.busi_type = "206"; + // // publicData.oper_method = "11"; + // } + // + // Object.assign(config.data, publicParams, publicData); + // } else if (['310400'].includes(cmdId)) { + // console.log('publicParams', publicParams, publicData); + // config.data.memberOperInfoVo = { + // ...publicParams, + // ...publicData, + // ori_value: '', + // new_value: '', + // oper_method: 1, + // trans_type: 105, + // busi_type: 222, + // }; + // } else if (['310635', '4', '402', '401'].includes(cmdId)) { + // config.data.trans_type = '101'; + // config.data.client_type = publicData.client_type; + // config.data.browser_brand = publicData.browser_brand; + // config.data.os_name = publicData.os_name; + // config.data.os_version = publicData.os_version; + // config.data.device_platform = publicData.device_platform; + // config.data.device_model = publicData.device_model; + // config.data.device_number = publicData.device_number; + // config.data.device_fingerprint = publicData.device_fingerprint; + // } + // + // console.log('config.data', config.data); + // } + + const sendStr = enD(rk, formatSendData(config.data, toNumber(paramType))); + const sendDateStr = enD(rk, t.toString()); + const checkOr = enC(rk, vk, sendDateStr); + + headers.cmdId = cmdId; + headers.aseqId = config.app.aseqId; + headers.nc = config.app.nc; + headers.tid = tid ?? tenantInfo.tid ?? ''; + // 试玩游戏cust_id=0 header需要保持一致 + headers.custId = (config.data?.cust_id === 0 ? '0' : '') || userInfo?.cust_id || ''; + headers.reqId = uuid(32, 16); + // headers.isMobileOpen = isMobile() ? '1' : '0'; + headers.isMobileOpen = '1'; + // headers.languageNum = langToNum(language.value); + headers.languageNum = 0; + headers.project = 'tiyu-app'; + headers.platform = getBetPlatform(); // 哪端 + headers.checkOr = checkOr; + headers.pwds = pwds; + headers.datetime = t; + headers.tbc = md5(t + 'fT6phq0wkOPRlAoyToidAnkogUV7tBBD'); + headers.reqKey = getRequestKey(cmdId, config.data); // 每一个接口请求的唯一key,前端用 + + if (toNumber(headerType) === 1) { + const grantType = 'password'; + const scope = 'read write'; + const signature = `react_clientgrant_type=${grantType}scope=${scope}cmd_id=${cmdId}react`; + headers.signature = md5(signature); + } else if (toNumber(headerType) === 2) { + const authorization = `Bearer ${userInfo?.access_token || ''}`; + const signature = `react_clientauthorization=${authorization}cmd_id=${cmdId}react`; + headers.authorization = authorization; + headers.signature = md5(signature); + } else if (toNumber(headerType) === 3) { + const grantType = 'refresh_token'; + const scope = ''; + const signature = `react_clientgrant_type=${grantType}scope=${scope}cmd_id=${cmdId}react`; + headers.signature = md5(signature); + } + + // console.log(headers, cmdId, '<------ request headers'); + localStorage.getItem('SHOW_DATA') && + console.error(cmdId, '最终请求参数', formatSendData(config.data, toNumber(paramType))); // 查看最终请求参数 + console.log(cmdId, 'request data --->', config.data); + return { + headers: { ...reset, ...headers }, + data: sendStr, + }; +}; + +// 解释响应数据 +export const parseResponse = (response: AxiosResponse): Promise> => { + try { + const { headers, data } = response; + const reqHeaders = response.config?.headers || {}; + // if (reqHeaders.cmdId == 310122) { + // console.log(data, reqHeaders.cmdId, '<<<<<<<<<<<<<<<<<<<<<<<<<< parseResponse data'); + // } + if (isString(data) && data.length > 0 && !startsWith(data, '')) { + const drk = dnP(config.app.vk, headers.pwds ?? '').substring(0, 8); + const dm = dnD(drk, data); + const dc = enC(drk, config.app.vk, enD(drk, toString(headers.datetime))); + // if (reqHeaders.cmdId == 310122) { + // console.log(dm, JSON.parse(dm), reqHeaders.cmdId); + // } + localStorage.getItem('SHOW_DATA') && + console.error(reqHeaders.cmdId, dm ? JSON.parse(dm) : dm); // 查看请求返回的数据 + if (!dm) { + throw new NetworkError({ + key: '', + tag: 'Network error 1', + info: '数据为空', + origin: '', + cmd: reqHeaders.cmdId, + }); + } + if (dc !== headers.checkor) { + throw new NetworkError({ + key: '', + tag: 'Network error 2', + info: '返回数据异常', + origin: '', + cmd: reqHeaders.cmdId, + }); + } + + const resData: any = JSON.parse(dm); + console.log( + JSON.parse(JSON.stringify(resData)), + reqHeaders.cmdId, + '<<<<<<<<<<<<<<<<<<<<<<<<<< parseResponse resData' + ); + if (resData) { + if (resData.exLevel) { + // 接口请求的错误处理 + let err: any; + // 预存奖励领取的时候 返回'0'提示 + if ([724209].includes(+reqHeaders.cmdId)) { + throw { + key: '', + tag: 'Network error 3', + info: resData.exMessage, + origin: resData, + cmd: reqHeaders.cmdId, + code: resData.exCode, + }; + } else { + err = new NetworkError({ + key: '', + tag: 'Network error 3', + info: resData.exMessage, + origin: resData, + cmd: reqHeaders.cmdId, + code: resData.exCode, + }); + } + // 版本号不对,强制更新 + if (err.code === 1108) { + err.update = true; + } else if ([1200, 1201, 1109, 1112, 1202, 1007].includes(+err.code)) { + // 1200 refresh_token错误 + // 1201 access_token错误 + // 1112 IP限制 + err.logout = true; // 退出登录 + err.tag = 'Network error 4'; + err.logoutMessage = '返回异常'; + } + throw err; + } else if (resData.error) { + throw new NetworkError({ + key: '', + tag: 'Network error 5', + info: resData.error_description, + origin: resData, + cmd: reqHeaders.cmdId, + code: resData.exCode, + }); + } else if (resData.response_code === '0') { + // 回收第三方金额 没有的的时候 也是返回'0' + // 预存奖励领取的时候 返回'0'提示 + if ([3911381, 724209].includes(+reqHeaders.cmdId)) { + resData.response_code = '1'; + } else { + throw new NetworkError({ + key: '', + tag: 'Network error 8', + info: resData.msg || '操作失败', + origin: resData, + cmd: reqHeaders.cmdId, + code: resData.exCode, + }); + } + } + } else { + if (!isNumber(toNumber(resData))) { + throw new NetworkError({ + key: '', + tag: 'Network error 1', + info: '数据为空', + origin: '', + cmd: reqHeaders.cmdId, + }); + } + } + return Promise.resolve({ type: NetworkTypeEnum.SUCCESS, data: resData }); + } else { + localStorage.getItem('SHOW_DATA') && console.error(reqHeaders.cmdId, data); // 查看请求返回的原始数据 + throw new NetworkError({ + key: '', + tag: 'Network error 7', + info: '请求没有返回任何数据', + // origin: context || response.toString(), + cmd: reqHeaders.cmdId, + code: -1, + }); + } + } catch (e) { + // // 404等错误处理 + // if (typeof context === 'object') { + // errStr = JSON.stringify(context); + // } else { + // const arr = context.match(/title[\s\S]*?title/g); + // if (arr && arr.length !== 0) { + // errStr = arr[0].replace(/title>/g, '').replace(/<\/title/g, ''); + // } + // } + // let logout = false; + // if (errStr.indexOf('invalid_token') !== -1) { + // logout = true; + // } + // // 类似这种错误的时候 跳到登录页 "error":"access_denied" "error":"unauthorized" + // if (errStr.indexOf('access_denied') !== -1 || errStr.indexOf('unauthorized') !== -1) { + // logout = true; + // } + // err = new NetworkError({ + // key: key, + // tag: 'Network error 6', + // info: errStr, + // origin: context, + // cmd: reqHeaders.cmdId, + // code: -1, + // logout: logout, + // }); + return Promise.reject({ type: NetworkTypeEnum.ERROR, data: e }); + } +};