Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ts req #45

Open
huenchao opened this issue Sep 23, 2024 · 0 comments
Open

ts req #45

huenchao opened this issue Sep 23, 2024 · 0 comments

Comments

@huenchao
Copy link
Owner

huenchao commented Sep 23, 2024

import { sendLog } from "~background/log";
import { ENV, ENV_TAG, STORAGE_KEY_WANGWANG_MTOP_TOKEN } from "~common/const";
import { getExtensionLocalStorage } from "~common/utils";

export const CODE_NOT_LOGIN = 401;

interface MtopRequestConfig {
  api: string;
  v: string;
  data: any;

  method?: 'GET' | 'POST';

  prefix?: string;
  subDomain?: string;
  mainDomain?: string;
  appKey?: number;
  jsv?: string;
  type?:string
  ecode?: number;
  isSec?: number | string;
  Referer?: string;
  Origin?:string;
  referrerPolicy?: string;
  noWapa?: boolean;
  ignoreLogin?: boolean;
}

interface MtopResponse<T = any> {
  api: string;
  c?: string;
  data: T;
  ret: string[]
  traceId: string;
  v: string;
}

const DEFAULT_MTOP_REQUEST_CONFIG: Partial<MtopRequestConfig> = {
  v: '1.0',
  prefix: 'acs',
  subDomain: 'm',
  mainDomain: 'taobao.com',
  appKey: 12574478,
  jsv: '2.7.3',
  method: 'GET',
}


const MIN_RULE_ID = 1;
const MAX_RULE_ID = 10000;
let ruleId = MIN_RULE_ID;

export async function mtopRequest<T> (config: MtopRequestConfig) {
  const mergedConfig: MtopRequestConfig = {
    ...DEFAULT_MTOP_REQUEST_CONFIG,
    ...config
  }

  if (ENV_TAG !== ENV.PRODUCTION && !mergedConfig.noWapa) {
    mergedConfig.subDomain = 'wapa';
  }

  const method = mergedConfig.method;

  const fetchOnce = async () => {
    let { [STORAGE_KEY_WANGWANG_MTOP_TOKEN]: token } = await getExtensionLocalStorage(STORAGE_KEY_WANGWANG_MTOP_TOKEN);
  
    const now = Date.now();
    const sign = getSign(token, now, mergedConfig.appKey, mergedConfig.data);
  
    const url = new URL(`https://${mergedConfig.prefix}.${mergedConfig.subDomain}.${mergedConfig.mainDomain}/h5/${mergedConfig.api}/${mergedConfig.v}/`);
  
    url.searchParams.append('api', mergedConfig.api);
    url.searchParams.append('v', mergedConfig.v);
    url.searchParams.append('dataType', 'json');
    url.searchParams.append('type', 'originaljson');
    url.searchParams.append('jsv', mergedConfig.jsv);
    url.searchParams.append('appKey', mergedConfig.appKey.toString());
    url.searchParams.append('t', now.toString());
    url.searchParams.append('sign', sign);
    if(typeof mergedConfig.isSec !== 'undefined'){
        url.searchParams.append('isSec', mergedConfig.isSec.toString());
    }
    if (typeof mergedConfig.ignoreLogin !== 'undefined') {
      url.searchParams.append('ignoreLogin', mergedConfig.ignoreLogin.toString());
    }

    // 要用 URLSearchParams ,用 FormData 的话校验会失败,提示非法请求
    let formData: URLSearchParams = null;

    if (method === 'POST') {
      formData = new URLSearchParams();
      formData.append('data', JSON.stringify(mergedConfig.data));
    } else {
      url.searchParams.append('data', JSON.stringify(mergedConfig.data));
    }
  
    let statusCode = -1;
    
    return fetch(url, {
      "referrerPolicy":  mergedConfig.referrerPolicy ||  "strict-origin-when-cross-origin",
      "body": formData,
      "method": method,
      "mode": "cors",
      "credentials": "include"
    }).then(response => {
      if (!response.ok) {
        statusCode = response.status;
        return response.text().then(errorText => Promise.reject(new Error(errorText)));
      }
      return response.json() as Promise<MtopResponse<T>>;
    }).catch(e => {
      console.error(mergedConfig.api, e);
      sendLog({
        type: 'error',
        target: 'mtop',
        extra: {
          statusCode,
          message: e.message,
          request: {
            ...mergedConfig,
            data: mergedConfig.method === 'POST' ? void 0 : mergedConfig.data,
          }
        }
      });
      return;
    })
  }

  let retryCount = 0;

  // 在每次mtop调用前,设置拦截规则,取时间戳最后八位作为 ruleId
  const tempDynamicRuleId = ruleId;
  ruleId++;
  if (ruleId > MAX_RULE_ID) {
    ruleId = 1;
  }

  await new Promise(resolve => {
    chrome.declarativeNetRequest.updateDynamicRules({
      removeRuleIds: [tempDynamicRuleId]
    }, resolve);
  });

  const Referer = mergedConfig.Referer ||  "https://www.xxxx.com/";
  const Origin = mergedConfig.Origin ||  "https://www.xxxx.com";
  
  await new Promise(resolve => {
    chrome.declarativeNetRequest.updateDynamicRules({
      addRules: [{
        id: tempDynamicRuleId,
        priority: 1,
        action: {
          type: 'modifyHeaders',
          requestHeaders: [
            { header: "Origin", operation: "set", value: Origin },
            { header: "Referer", operation: "set", value: Referer },
          ]
        },
        condition: {
          urlFilter: mergedConfig.api,
          resourceTypes: ["xmlhttprequest"]
        }
      }]
    } as any, resolve);
  })

  // token失效时重试
  try {
    while (retryCount < 4) {
      retryCount++;
      const res = await fetchOnce();
      
      if (!res) {
        return;
      }
  
      const { data, ret } = res;
  
      if (Object.keys(data).length || ret?.[0].includes('SUCCESS')) {
        return data;
      } else if (ret[0]) {
        // 非法请求 or 令牌为空
        if (ret[0].includes('FAIL_SYS_ILLEGAL_ACCESS') || ret[0].includes('FAIL_SYS_TOKEN_EMPTY')) {
          // 会返回一个 c 字段,提供新的  _m_h5_tk 和 _m_h5_tk_enc
          if (res.c) {
            const [_m_h5_tk, _m_h5_tk_enc] = res.c.split(';')
            const newToken = _m_h5_tk.split('_')[0];
            // 更新token到存储
            await chrome.storage.local.set({ [STORAGE_KEY_WANGWANG_MTOP_TOKEN]: newToken });
          }
        } else if (ret[0].includes('FAIL_SYS_SESSION_EXPIRED')) {
          // Session过期 表示未登录
          return CODE_NOT_LOGIN;
        } else {
          sendLog({
            type: 'error',
            target: 'mtop',
            extra: {
              statusCode: 200,
              message: ret[0],
              request: {
                ...mergedConfig,
                data: mergedConfig.method === 'POST' ? void 0 : mergedConfig.data,
              }
            }
          });
        }
      }
    }
  
    return;
  } finally {
    chrome.declarativeNetRequest.updateDynamicRules({
      removeRuleIds: [tempDynamicRuleId]
    });
  }
}

function getSign (token: string, timestamp: number, appKey: number, data: any) {
  return md5(token + '&' + timestamp + "&" + appKey + "&" + JSON.stringify(data));
}

export function md5(string: any) {
  function rotateLeft(lValue: any, iShiftBits: any) {
      return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
  }
  function addUnsigned(lX: any, lY: any) {
      var lX4, lY4, lX8, lY8, lResult;
      lX8 = (lX & 0x80000000);
      lY8 = (lY & 0x80000000);
      lX4 = (lX & 0x40000000);
      lY4 = (lY & 0x40000000);
      lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
      if (lX4 & lY4) {
          return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
      }
      if (lX4 | lY4) {
          if (lResult & 0x40000000) {
              return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
          } else {
              return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
          }
      } else {
          return (lResult ^ lX8 ^ lY8);
      }
  }

  function f(x: any, y: any, z: any) {
      return (x & y) | ((~x) & z);
  }

  function g(x: any, y: any, z: any) {
      return (x & z) | (y & (~z));
  }

  function h(x: any, y: any, z: any) {
      return (x ^ y ^ z);
  }

  function i(x: any, y: any, z: any) {
      return (y ^ (x | (~z)));
  }

  function FF(a: any, b: any, c: any, d: any, x: any, s: any, ac: any) {
      a = addUnsigned(a, addUnsigned(addUnsigned(f(b, c, d), x), ac));
      return addUnsigned(rotateLeft(a, s), b);
  }

  function GG(a: any, b: any, c: any, d: any, x: any, s: any, ac: any) {
      a = addUnsigned(a, addUnsigned(addUnsigned(g(b, c, d), x), ac));
      return addUnsigned(rotateLeft(a, s), b);
  }

  function HH(a: any, b: any, c: any, d: any, x: any, s: any, ac: any) {
      a = addUnsigned(a, addUnsigned(addUnsigned(h(b, c, d), x), ac));
      return addUnsigned(rotateLeft(a, s), b);
  }

  function II(a: any, b: any, c: any, d: any, x: any, s: any, ac: any) {
      a = addUnsigned(a, addUnsigned(addUnsigned(i(b, c, d), x), ac));
      return addUnsigned(rotateLeft(a, s), b);
  }

  function convertToWordArray(string: any) {
      var lWordCount;
      var lMessageLength = string.length;
      var lNumberOfWords_temp1 = lMessageLength + 8;
      var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
      var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
      var lWordArray = new Array(lNumberOfWords - 1);
      var lBytePosition = 0;
      var lByteCount = 0;
      while (lByteCount < lMessageLength) {
          lWordCount = (lByteCount - (lByteCount % 4)) / 4;
          lBytePosition = (lByteCount % 4) * 8;
          lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
          lByteCount++;
      }
      lWordCount = (lByteCount - (lByteCount % 4)) / 4;
      lBytePosition = (lByteCount % 4) * 8;
      lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
      lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
      lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
      return lWordArray;
  }

  function wordToHex(lValue: any) {
      var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
      for (lCount = 0; lCount <= 3; lCount++) {
          lByte = (lValue >>> (lCount * 8)) & 255;
          WordToHexValue_temp = "0" + lByte.toString(16);
          WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
      }
      return WordToHexValue;
  }

  function utf8Encode(string: any) {
      string = string.replace(/\r\n/g, "\n");
      var utftext = "";

      for (var n = 0; n < string.length; n++) {

          var c = string.charCodeAt(n);

          if (c < 128) {
              utftext += String.fromCharCode(c);
          }
          else if ((c > 127) && (c < 2048)) {
              utftext += String.fromCharCode((c >> 6) | 192);
              utftext += String.fromCharCode((c & 63) | 128);
          }
          else {
              utftext += String.fromCharCode((c >> 12) | 224);
              utftext += String.fromCharCode(((c >> 6) & 63) | 128);
              utftext += String.fromCharCode((c & 63) | 128);
          }

      }

      return utftext;
  }

  var x = [],
   k, AA, BB, CC, DD, a, b, c, d,
   S11 = 7, S12 = 12, S13 = 17, S14 = 22,
   S21 = 5, S22 = 9 , S23 = 14, S24 = 20,
   S31 = 4, S32 = 11, S33 = 16, S34 = 23,
   S41 = 6, S42 = 10, S43 = 15, S44 = 21;

  string = utf8Encode(string);

  x = convertToWordArray(string);

  a = 0x67452301;
  b = 0xEFCDAB89;
  c = 0x98BADCFE;
  d = 0x10325476;

  for (k = 0; k < x.length; k += 16) {
      AA = a;
      BB = b;
      CC = c;
      DD = d;
      a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
      d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
      c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
      b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
      a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
      d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
      c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
      b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
      a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
      d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
      c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
      b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
      a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
      d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
      c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
      b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
      a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
      d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
      c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
      b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
      a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
      d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
      c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
      b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
      a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
      d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
      c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
      b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
      a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
      d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
      c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
      b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
      a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
      d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
      c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
      b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
      a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
      d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
      c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
      b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
      a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
      d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
      c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
      b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
      a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
      d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
      c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
      b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
      a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
      d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
      c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
      b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
      a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
      d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
      c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
      b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
      a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
      d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
      c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
      b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
      a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
      d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
      c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
      b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
      a = addUnsigned(a, AA);
      b = addUnsigned(b, BB);
      c = addUnsigned(c, CC);
      d = addUnsigned(d, DD);
  }

  var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);

  return temp.toLowerCase();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant