/* 小芒商城助手 [Script] # > 小芒商城助手 ^https?:\/\/*\.api\.mgtv\.com url script-request-body https://git.jojo21.top/shawenguan/Quantumult-X/raw/master/Scripts/mangguo/mgecomHelper.js ^https?:\/\/*\.api\.mgtv\.com url script-response-body https://git.jojo21.top/shawenguan/Quantumult-X/raw/master/Scripts/mangguo/mgecomHelper.js [MITM] hostname = api.mgtv.com */ const scriptName = `小芒商城助手`; const magicJS = MagicJS(scriptName, "INFO"); const MGEcomConstKey = { AllUserInfo: 'mgeComAllUserInfo', AllUserConfig: 'mgeComAllUserConfig', }; const gUserAgent = `Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Html5Plus/1.0 (Immersed/20) uni-app`; const gHost = `api.wubian.pro`; let gToken = magicJS.data.read(WuBianConstKey.Token, ''); const gCommonHeaders = { 'Accept': `*/*`, 'Accept-Encoding': `gzip, deflate, br`, 'Connection': `keep-alive`, 'Content-Type': `application/json`, 'Cookie': `token=${gToken}`, 'Host': gHost, 'User-Agent': gUserAgent, 'CLIENT-TYPE': `APP`, 'token': gToken, 'Accept-Language': `zh-CN,zh-Hans;q=0.9` }; let gRetBody; let gAllStateData = { } let SignHelper = (function () { const goldenRatio = 2654435769; function decodeByteArray(byteArray, hasLengthPrefix) { const length = byteArray.length; let totalLength = length << 2; if (hasLengthPrefix) { const lastByte = byteArray[length - 1]; if (totalLength -= 4, lastByte < totalLength - 3 || lastByte > totalLength) return ""; totalLength = lastByte; } for (let i = 0; i < length; i++) { byteArray[i] = String.fromCharCode(255 & byteArray[i], byteArray[i] >>> 8 & 255, byteArray[i] >>> 16 & 255, byteArray[i] >>> 24 & 255); } const resultString = byteArray.join(""); return hasLengthPrefix ? resultString.substring(0, totalLength) : resultString; } function stringToByteArray(str, hasLengthPrefix) { const length = str.length; let byteArray, arrayLength = length >> 2; if (length & 3 !== 0) arrayLength++; if (hasLengthPrefix) { byteArray = new Array(arrayLength + 1); byteArray[arrayLength] = length; } else { byteArray = new Array(arrayLength); } for (let i = 0; i < length; ++i) { byteArray[i >> 2] |= str.charCodeAt(i) << ((3 & i) << 3); } return byteArray; } function unsignedRightShift(value) { return 4294967295 & value; } function customHashFunction(value, key, accumulator, index, arrayLength, keys) { return (accumulator >>> 5 ^ key << 2) + (key >>> 3 ^ accumulator << 4) ^ (value ^ key) + (keys[3 & index ^ arrayLength] ^ accumulator); } function ensureLength(byteArray) { if (byteArray.length < 4) byteArray.length = 4; return byteArray; } function encodeByteArray(byteArray, keys) { const length = byteArray.length; const lastIndex = length - 1; let temp, prevByte, nextByte; let sum = 0; for (prevByte = byteArray[lastIndex], sum = 0 | Math.floor(6 + 52 / length); sum > 0; --sum) { sum = unsignedRightShift(sum + goldenRatio); nextByte = sum >>> 2 & 3; for (let i = 0; i < lastIndex; ++i) { temp = byteArray[i + 1]; prevByte = byteArray[i] = unsignedRightShift(byteArray[i] + customHashFunction(sum, temp, prevByte, i, nextByte, keys)); } temp = byteArray[0]; prevByte = byteArray[lastIndex] = unsignedRightShift(byteArray[lastIndex] + customHashFunction(sum, temp, prevByte, lastIndex, nextByte, keys)); } return byteArray; } function utf8Encode(str) { if (/^[\x00-\x7f]*$/.test(str)) return str; const utf8Str = []; const length = str.length; for (let i = 0, j = 0; i < length; ++i, ++j) { const charCode = str.charCodeAt(i); if (charCode < 128) { utf8Str[j] = str.charAt(i); } else if (charCode < 2048) { utf8Str[j] = String.fromCharCode(192 | charCode >> 6, 128 | 63 & charCode); } else { if (charCode >= 55296 && charCode <= 57343) { if (i + 1 < length) { const nextCharCode = str.charCodeAt(i + 1); if (charCode < 56320 && 56320 <= nextCharCode && nextCharCode <= 57343) { const surrogatePair = 65536 + ((1023 & charCode) << 10 | 1023 & nextCharCode); utf8Str[j] = String.fromCharCode(240 | surrogatePair >> 18 & 63, 128 | surrogatePair >> 12 & 63, 128 | surrogatePair >> 6 & 63, 128 | 63 & surrogatePair); ++i; continue; } } throw new Error("Malformed string"); } utf8Str[j] = String.fromCharCode(224 | charCode >> 12, 128 | charCode >> 6 & 63, 128 | 63 & charCode); } } return utf8Str.join(""); } function encryptString(str, key) { if (str.length === 0) return str; str = utf8Encode(str); key = utf8Encode(key); return decodeByteArray(encodeByteArray(stringToByteArray(str, true), ensureLength(stringToByteArray(key, false))), false); } function base64Encode(str1, str2) { return btoa(encryptString(str1, str2)); } function generateCustomString(str1, str2) { const md5 = createWMd5(); return md5.hex_md5_32(`string xiaomang = "${str1}|${str2}";`); } function generateUuidWithVersion(uuid, version, offset) { const data = { uuid: uuid, reunixtime: Math.round((Date.now() - offset) / 1000), }; const customString = generateCustomString(uuid, version); return base64Encode(JSON.stringify(data), customString); } function generateAnotherCustomString(str1, str2) { const md5 = createWMd5(); return md5.hex_md5_32(`string ma = "${str1}|${str2}";`); } function generateRandomSalt() { const multiplier = 38833; const randomValue = Math.floor(Math.random() * 2 ** 32) + 1; return randomValue * multiplier; } function generateSignedUuid(uuid, version, offset, maBig, maSi) { let i = 0; let signedUuid = ""; while (!(signedUuid <= maBig && signedUuid.includes(maSi))) { if (++i > 100000) return ""; signedUuid = generateUuidWithSalt(uuid, version, offset); } console.log(i); return signedUuid; } function generateUuidWithSalt(uuid, version, offset) { const data = { uuid: uuid, reunixtime: Math.round((Date.now() - offset) / 1000), salt: generateRandomSalt(), }; const customString = generateAnotherCustomString(uuid, version); return base64Encode(JSON.stringify(data), customString); } async function getDySign(uuid) { let stateData = await getStateData(); const { userConfig, userInfo, diffTime } = stateData; return generateUuidWithVersion(userInfo.uuid, userConfig.version, diffTime); } async function getMaSign(uuid) { let stateData = await getStateData(); const { userConfig, userInfo, diffTime } = stateData; return generateSignedUuid(userInfo.uuid || "", userConfig.version, diffTime, userConfig.version_ma_big, userConfig.version_ma_si); } return { getDySign: getDySign, getMaSign: getMaSign, }; })(); async function Main() { if (magicJS.isStrictRequest) { magicJS.checkRecordRequestBody(); } if (magicJS.isRequest) { checkHandleRequest(); } else { updateHeaders(); } magicJS.notification.msg(''); if (gRetBody) { magicJS.done({ body: JSON.stringify(gRetBody) }); } else { magicJS.done(); } } function checkHandleRequest() { const url = $request.url; const path = $request.path; magicJS.logger.info(`请求url=${url}#${$request.method}`); magicJS.logger.info(`请求body=${magicJS.getRequestBody()}`); if ($request && $request.method != 'OPTIONS') { switch (path) { case '/GetUserInfo': handleUserInfo(); break; case '/user/home/info': handleUserHomeInfo(); break; default: break; } } } function handleHeaders() { } function updateHeaders() { } function getResponsePlainData() { let data = magicJS.getResponseBody(); if (!data) { return; } try { return JSON.parse(data); } catch (err) { magicJS.logger.info(data); magicJS.logger.error(err); } } function getRequestPlainData() { let data = magicJS.getRequestBody(); let reqData = null; if (data) { reqData = JSON.parse(data); } else { reqData = magicJS.parseQueryStr($request.url); } return reqData; } function getQueryPlainData() { let params = magicJS.parseQueryStr($request.url); return params; } function handleUserInfo() { let rspData = getResponsePlainData(); if (!rspData) { return; } if (rspData.code != 200) { return; } let allUserDict = magicJS.data.read(MGEcomConstKey.AllUserInfo, {}); const userInfo = rspData.data; if (userInfo) { let uuid = userInfo.uuid; let mobile = userInfo.relate_mobile; if (userInfo.ticket) { allUserDict[uuid] = userInfo; allUserDict[mobile] = userInfo; setDiffTime(Date.now() - 1e3 * homeInfo.unixtime); } else { delete allUserDict[uuid]; delete allUserDict[mobile]; } } else { let reqData = getQueryPlainData(); let uuid = reqData.uuid; let oldUserInfo = allUserDict[uuid]; if (oldUserInfo) { let mobile = oldUserInfo.relate_mobile; delete allUserDict[uuid]; delete allUserDict[mobile]; } } magicJS.data.write(MGEcomConstKey.AllUserInfo, allUserDict); } function handleUserHomeInfo() { let rspData = getResponsePlainData(); if (!rspData) { return; } if (rspData.code != 200) { return; } const homeInfo = rspData.data; let allConfigDict = magicJS.data.read(MGEcomConstKey.AllUserConfig, {}); let reqData = getQueryPlainData(); let uuid = reqData.uuid; allConfigDict[uuid] = homeInfo; magicJS.data.write(MGEcomConstKey.AllUserConfig, allConfigDict); setDiffTime(Date.now() - 1e3 * homeInfo.unixtime); } async function getStateData(uuid) { let state = gAllStateData[uuid]; if (!state) { state = { diffTime: 0, userInfo: null, userConfig: null, }; gAllStateData[uuid] = state; }; if (!state.userInfo) { state.userConfig = await getUserConfig(uuid); } if (!state.userInfo) { state.userInfo = await getUserInfo(uuid); } return state; } async function getUserConfig(uuid) { let allUserDict = magicJS.data.read(MGEcomConstKey.AllUserInfo, {}); let userConfig = allUserDict[uuid]; if (!userConfig) { } return userConfig; } async function getUserInfo(uuid) { let allConfigDict = magicJS.data.read(MGEcomConstKey.AllUserConfig, {}); let userInfo = allConfigDict[uuid]; if (!userInfo) { } return userInfo; } async function getDiffTime() { return 0; } function setDiffTime(diffTime) { } Main().catch((e) => magicJS.logger.log(`-\n ${e}`)).finally(() => magicJS.done());