faker3/utils/baseH5st.js
2024-06-28 15:38:28 +08:00

337 lines
11 KiB
JavaScript

const CryptoJS = require("crypto-js");
const {BaseUtils} = require("./baseUtils");
const os = require('os');
class BaseH5st {
constructor(url, cookieStr, userAgent) {
global.baseUtils || new BaseUtils();
baseUtils.changeEnv(url, cookieStr, userAgent);
this.ErrCodes = {
UNSIGNABLE_PARAMS: 1, APPID_ABSENT: 2, TOKEN_EMPTY: 3, GENERATE_SIGNATURE_FAILED: 4, UNHANDLED_ERROR: -1
};
this._defaultAlgorithm = {};
this._debug = false;
this.settings = {
debug: !1, preRequest: !1, timeout: 2,
};
}
_log(log) {
if (this._debug) {
console.log('[sign]', log)
}
}
getSync(t) {
let item = window.localStorage.getItem(t);
if (item) {
let r = JSON.parse(item);
if (!r || !r.t || !r.e || 0 === r.e || new Date - r.t >= 1e3 * r.e) {
this.removeSync(t);
return "";
}
return r.v
}
return ""
}
setSync(t, r, n, e) {
let i = {
v: r,
t: (new Date).getTime(),
e: "number" != typeof n.expire ? 0 : n.expire
}
window.localStorage.setItem(t, JSON.stringify(i));
}
removeSync(t) {
window.localStorage.removeItem(t)
}
__genDefaultKey(t, z) {
let A = "";
let S = CryptoJS.enc.Utf8.stringify(CryptoJS.enc.Base64.parse(baseUtils.decodeBase64URL(this.__parseToken(t, 16, 28)))),
B = S.match(/^[123]([x+][123])+/);
if (B) {
var j = B[0]["split"](""),
M = "";
j.forEach((r) => {
if (isNaN(r)) {
if (["+", "x"].includes(r)) M = r;
} else {
var a = `local_key_${r}`;
if (this._defaultAlgorithm[a]) {
switch (M) {
case "+":
A = `${A}${this.__algorithm(a, z, t)}`;
break;
case "x":
A = this.__algorithm(a, A, t);
break;
default:
A = this.__algorithm(a, z, t);
}
}
}
})
}
this._log(`__genDefaultKey input=${z},express=${S},key=${A}`)
return A;
}
__algorithm(t, r, n) {
return t === "local_key_3" ? this._defaultAlgorithm[t](r, n).toString(CryptoJS.enc.Hex) : this._defaultAlgorithm[t](r).toString(CryptoJS.enc.Hex);
}
__parseToken(t, r, n) {
if (t) return baseUtils.getDefaultMethod(t, 'slice').call(t, r, n);
return "";
}
__parseAlgorithm(t, r) {
this["_token"] = t || "";
this.__genKey = r && new Function(`return ${r}`)() || null;
return !(!this["_token"] || !this.__genKey);
}
__genSign(t, r) {
var y = baseUtils.getDefaultMethod(r, 'map')["call"](r, function (t) {
return t["key"] + ":" + t.value;
})["join"]("&");
var d = CryptoJS.HmacSHA256(y, t).toString(CryptoJS.enc.Hex);
this._log(`__genSign, paramsStr:${y}, signedStr:${d}`);
return d;
}
async __requestAlgorithmOnce() {
await this.__requestAlgorithm();
}
async __requestAlgorithm() {
this._log("__requestAlgorithm start.");
var r = this.envCollect(0);
r.ai = this._appId;
r.fp = this._fingerprint;
var n = JSON.stringify(r, null, 2);
this._log(`__requestAlgorithm envCollect=${n}`);
var e = this.aes(n , 'wm0!@w-s#ll1flo(', "0102030405060708");
var dt = {
fingerprint: this._fingerprint, appId: this._appId, version: this._version, env: e, debug: this._debug,
};
try {
var {data} = await api({
url: "https://cactus.jd.com/request_algo",
method: "post",
data: {
version: dt.version,
fp: dt.fingerprint,
appId: dt.appId,
timestamp: Date.now(),
platform: "web",
expandParams: dt.env,
fv: this.v,
},
headers: {
"Content-Type": "application/json;charset=utf-8",
Origin: "https://cactus.jd.com",
Host: "cactus.jd.com",
accept: "*/*",
"User-Agent": navigation.userAgent,
},
});
if (data && data.status === 200 && data.data && data.data.result) {
var c = data.data.result;
if (c.algo && c.tk && c.fp) {
var l = c.fp === this._fingerprint,
p = l ? this.getSync(this._storageFpKey, 1) : "",
d = p && c.fp === p;
if (d) {
var z = this.__parseToken(c.tk, 13, 15);
var x = parseInt(z, 16);
var w = x * 60 * 60;
this.setSync(this._storagetokenKey, CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(c.tk)), {
expire: w,
});
this.setSync(this._storageAlgnKey, CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(c.algo)), {
expire: w,
});
}
this._log(`__requestAlgorithm request success!, check memory fp:${l}, check storage fp:${d}, token:${c.tk}, storageFp:${p}, fp:${c.fp}`);
} else {
throw new Error("data.result format error.");
}
} else {
throw new Error("request params error.");
}
} catch (error) {
throw new Error(`request error, ${error.code}, ${error.message}`);
}
this._log(this._debug, "__requestAlgorithm end.");
}
__checkParams(t) {
let u = null;
if (!this._appId) {
u = {
code: this.ErrCodes.APPID_ABSENT, message: "appId is required"
}
}
if (!baseUtils.isPlainObject(t)) {
u = {
code: this.ErrCodes.UNSIGNABLE_PARAMS, message: 'params is not a plain object'
}
}
if (baseUtils.isEmpty(t)) {
u = {
code: this.ErrCodes.UNSIGNABLE_PARAMS, message: 'params is empty'
}
}
if (baseUtils.containsReservedParamName(t)) {
u = {
code: this.ErrCodes.UNSIGNABLE_PARAMS, message: 'params contains reserved param name.'
}
}
if (u) {
this._onSign(u);
return null;
}
let o, e, r, n;
o = baseUtils.getDefaultMethod(e = baseUtils.getDefaultMethod(r = baseUtils.getDefaultMethod(n = Object.keys(t), 'sort').call(n), 'map').call(r, (function (e) {
return {key: e, value: t[e]}
})), 'filter').call(e, (function (t) {
return baseUtils.isSafeParamValue(t.value)
}))
if (o.length === 0) {
this._onSign({
code: this.ErrCodes.UNSIGNABLE_PARAMS, message: 'params is empty after excluding "unsafe" params',
});
return null;
}
return o;
}
__collect() {
var n = this.envCollect(1);
n.fp = this._fingerprint;
var e = JSON.stringify(n, null, 2);
this._log(`__collect envCollect=${e}`);
return this.aes(e, this.collectSecret, "0102030405060708");
}
async sign(params) {
try {
var Ot = Date.now();
var e = ["functionId", "appid", "client", "body", "clientVersion", "sign", "t", "jsonp"].reduce((function (e, r) {
var n = params[r];
return n && ("body" === r && (n = CryptoJS.SHA256(n).toString()), e[r] = n), e
}), {});
var o = this.__checkParams(e);
if (o == null) {
return e;
}
await this.__requestDeps();
let i = this.__collect();
let a = this.__makeSign(o, i);
this._log(`sign elapsed time!${Date.now() - Ot}ms`);
return Object.assign({}, e, a);
} catch (error) {
this._onSign({
code: this.ErrCodes.UNHANDLED_ERROR, message: 'unknown error'
})
this._log(`unknown error!${error.message}`);
return params;
}
}
envCollect(e) {
let info = {
pp: (() => {
let ptPin = baseUtils.extractPtPin(document.cookie);
if (ptPin) {
return {
"p1": ptPin,
"p2": ptPin
}
}
return {}
})(),
extend: {
bu1: this.bu1,
bu2: 0,
bu3: document.head.childElementCount,
bu4: 0,
bu5: 0,
l: 0,
ls: 0,
wd: 0,
wk: 0,
},
random: baseUtils.getRandomIDPro({size: 12, dictType: 'max', customDict: null}),
sua: (() => {
var regex = new RegExp("Mozilla/5.0 \\((.*?)\\)");
var matches = window.navigator.userAgent.match(regex);
return matches && matches[1] ? matches[1] : "";
})()
}
if (this.v) {
info.v = this.v
}
if (e == 0) {
Object.assign(info, {
"wc": /Chrome/.test(window.navigator.userAgent) && !window.chrome ? 1 : 0,
"wd": 0,
"l": navigator.language,
"ls": navigator.languages.join(","),
"ml": navigator.mimeTypes.length,
"pl": navigator.plugins.length,
"av": (() => {
let av = window.navigator.userAgent.match(/(?<=\/)[0-9]\.0[^'"\n]+/g);
return av.length > 0 ? av[0] : "";
})(),
"ua": window.navigator.userAgent,
"w": window.screen.width,
"h": window.screen.height,
"ow": window.outerWidth,
"oh": window.outerHeight,
"url": location.href,
"og": location.origin,
// "pf": os.platform(),
// "bu2": " at https://storage.360buyimg.com/webcontainer/js_security_v3_0.1.5.js:3833:21",
// "canvas": "07d433e77178ffb3c4358a1a92f3233f",
// "webglFp": "d714752d3e7330bcd7e2b332e7cbcb56",
"ccn": navigator.hardwareConcurrency,
"ai": this._appId,
"pr": 1,
"re": document.referrer,
"referer": (() => {
var i = new RegExp("[^?]*"),
u = document.referrer.match(i);
if (!u || !u[0]) return "";
return u[0];
})(),
"pp1": {
},
})
}
return info;
}
aes(message, key, iv) {
return CryptoJS.AES.encrypt(message, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(iv),
}).ciphertext.toString();
}
}
module.exports.BaseH5st = BaseH5st