205 lines
7.4 KiB
JavaScript
205 lines
7.4 KiB
JavaScript
|
let request = require("request");
|
||
|
let CryptoJS = require('crypto-js');
|
||
|
let qs = require("querystring");
|
||
|
Date.prototype.Format = function(fmt) {
|
||
|
var e,
|
||
|
n = this,
|
||
|
d = fmt,
|
||
|
l = {
|
||
|
"M+": n.getMonth() + 1,
|
||
|
"d+": n.getDate(),
|
||
|
"D+": n.getDate(),
|
||
|
"h+": n.getHours(),
|
||
|
"H+": n.getHours(),
|
||
|
"m+": n.getMinutes(),
|
||
|
"s+": n.getSeconds(),
|
||
|
"w+": n.getDay(),
|
||
|
"q+": Math.floor((n.getMonth() + 3) / 3),
|
||
|
"S+": n.getMilliseconds()
|
||
|
};
|
||
|
/(y+)/i.test(d) && (d = d.replace(RegExp.$1, "".concat(n.getFullYear()).substr(4 - RegExp.$1.length)));
|
||
|
for (var k in l) {
|
||
|
if (new RegExp("(".concat(k, ")")).test(d)) {
|
||
|
var t, a = "S+" === k ? "000" : "00";
|
||
|
d = d.replace(RegExp.$1, 1 == RegExp.$1.length ? l[k] : ("".concat(a) + l[k]).substr("".concat(l[k]).length))
|
||
|
}
|
||
|
}
|
||
|
return d;
|
||
|
}
|
||
|
|
||
|
function generateFp() {
|
||
|
let e = "0123456789";
|
||
|
let a = 13;
|
||
|
let i = '';
|
||
|
for (; a--;) i += e[Math.random() * e.length | 0];
|
||
|
return (i + Date.now()).slice(0, 16)
|
||
|
}
|
||
|
|
||
|
function getUrlData(url, name) {
|
||
|
if (typeof URL !== "undefined") {
|
||
|
let urls = new URL(url);
|
||
|
let data = urls.searchParams.get(name);
|
||
|
return data ? data : '';
|
||
|
} else {
|
||
|
const query = url.match(/\?.*/)[0].substring(1)
|
||
|
const vars = query.split('&')
|
||
|
for (let i = 0; i < vars.length; i++) {
|
||
|
const pair = vars[i].split('=')
|
||
|
if (pair[0] === name) {
|
||
|
return vars[i].substr(vars[i].indexOf('=') + 1);
|
||
|
}
|
||
|
}
|
||
|
return ''
|
||
|
}
|
||
|
}
|
||
|
class jxAlgo {
|
||
|
constructor(params = {}) {
|
||
|
this.appId = 10001
|
||
|
this.result = {}
|
||
|
this.timestamp = Date.now();
|
||
|
for (let i in params) {
|
||
|
this[i] = params[i]
|
||
|
}
|
||
|
}
|
||
|
set(params = {}) {
|
||
|
for (let i in params) {
|
||
|
this[i] = params[i]
|
||
|
}
|
||
|
}
|
||
|
get(key) {
|
||
|
return this[key]
|
||
|
}
|
||
|
async dec(url) {
|
||
|
if (!this.tk) {
|
||
|
this.fingerprint = generateFp();
|
||
|
await this.requestAlgo()
|
||
|
}
|
||
|
let obj = qs.parse(url.split("?")[1]);
|
||
|
let stk = obj['_stk'];
|
||
|
return this.h5st(this.timestamp, stk, url)
|
||
|
}
|
||
|
h5st(time, stk, url) {
|
||
|
stk = stk || (url ? getUrlData(url, '_stk') : '')
|
||
|
const timestamp = new Date(time).Format("yyyyMMddhhmmssSSS");
|
||
|
let hash1 = this.enCryptMethodJD(this.tk, this.fingerprint.toString(), timestamp.toString(), this.appId.toString(), CryptoJS).toString(CryptoJS.enc.Hex);
|
||
|
let st = '';
|
||
|
stk.split(',').map((item, index) => {
|
||
|
st += `${item}:${getUrlData(url, item)}${index === stk.split(',').length - 1 ? '' : '&'}`;
|
||
|
})
|
||
|
const hash2 = CryptoJS.HmacSHA256(st, hash1.toString()).toString(CryptoJS.enc.Hex);
|
||
|
const enc = (["".concat(timestamp.toString()), "".concat(this.fingerprint.toString()), "".concat(this.appId.toString()), "".concat(this.tk), "".concat(hash2)].join(";"))
|
||
|
this.result['fingerprint'] = this.fingerprint;
|
||
|
this.result['timestamp'] = this.timestamp
|
||
|
this.result['stk'] = stk;
|
||
|
this.result['h5st'] = enc
|
||
|
let sp = url.split("?");
|
||
|
let obj = qs.parse(sp[1])
|
||
|
if (obj.callback) {
|
||
|
delete obj.callback
|
||
|
}
|
||
|
let params = Object.assign(obj, {
|
||
|
'_time': this.timestamp,
|
||
|
'_': this.timestamp,
|
||
|
'timestamp': this.timestamp,
|
||
|
'sceneval': 2,
|
||
|
'g_login_type': 1,
|
||
|
'h5st': enc,
|
||
|
})
|
||
|
this.result['url'] = `${sp[0]}?${qs.stringify(params)}`
|
||
|
return this.result
|
||
|
}
|
||
|
token(user) {
|
||
|
let nickname = user.includes('pt_pin') ? user.match(/pt_pin=([^;]+)/)[1] : user;
|
||
|
let phoneId = this.createuuid(40, 'lc');
|
||
|
|
||
|
let token = this.md5(decodeURIComponent(nickname) + this.timestamp + phoneId + 'tPOamqCuk9NLgVPAljUyIHcPRmKlVxDy');
|
||
|
return {
|
||
|
'strPgtimestamp': this.timestamp,
|
||
|
'strPhoneID': phoneId,
|
||
|
'strPgUUNum': token
|
||
|
}
|
||
|
}
|
||
|
md5(encryptString) {
|
||
|
return CryptoJS.MD5(encryptString).toString()
|
||
|
}
|
||
|
createuuid(a, c) {
|
||
|
switch (c) {
|
||
|
case "a":
|
||
|
c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||
|
break;
|
||
|
case "n":
|
||
|
c = "0123456789";
|
||
|
break;
|
||
|
case "c":
|
||
|
c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||
|
break;
|
||
|
case "l":
|
||
|
c = "abcdefghijklmnopqrstuvwxyz";
|
||
|
break;
|
||
|
case 'cn':
|
||
|
case 'nc':
|
||
|
c = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||
|
break;
|
||
|
case "lc":
|
||
|
case "cl":
|
||
|
c = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||
|
break;
|
||
|
default:
|
||
|
c = "0123456789abcdef"
|
||
|
}
|
||
|
var e = "";
|
||
|
for (var g = 0; g < a; g++) e += c[Math.ceil(1E8 * Math.random()) % c.length];
|
||
|
return e
|
||
|
}
|
||
|
async requestAlgo() {
|
||
|
const options = {
|
||
|
"url": `https://cactus.jd.com/request_algo?g_ty=ajax`,
|
||
|
"headers": {
|
||
|
'Authority': 'cactus.jd.com',
|
||
|
'Pragma': 'no-cache',
|
||
|
'Cache-Control': 'no-cache',
|
||
|
'Accept': 'application/json',
|
||
|
'User-Agent': 'jdpingou;iPhone;4.9.4;12.4;ae49fae72d0a8976f5155267f56ec3a5b0da75c3;network/wifi;model/iPhone8,4;appBuild/100579;ADID/00000000-0000-0000-0000-000000000000;supportApplePay/1;hasUPPay/0;pushNoticeIsOpen/0;hasOCPay/0;supportBestPay/0;session/1;pap/JA2019_3111789;brand/apple;supportJDSHWK/1;Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
|
||
|
'Content-Type': 'application/json',
|
||
|
'Origin': 'https://st.jingxi.com',
|
||
|
'Sec-Fetch-Site': 'cross-site',
|
||
|
'Sec-Fetch-Mode': 'cors',
|
||
|
'Sec-Fetch-Dest': 'empty',
|
||
|
'Referer': 'https://st.jingxi.com/pingou/dream_factory/index.html?ptag=7155.9.4',
|
||
|
'Accept-Language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8,en;q=0.7'
|
||
|
},
|
||
|
'body': JSON.stringify({
|
||
|
"version": "1.0",
|
||
|
"fp": this.fingerprint,
|
||
|
"appId": this.appId.toString(),
|
||
|
"timestamp": this.timestamp,
|
||
|
"platform": "web",
|
||
|
"expandParams": ""
|
||
|
})
|
||
|
}
|
||
|
return new Promise(async resolve => {
|
||
|
request.post(options, (err, resp, data) => {
|
||
|
try {
|
||
|
if (data) {
|
||
|
data = JSON.parse(data);
|
||
|
if (data['status'] === 200) {
|
||
|
let result = data.data.result
|
||
|
this.tk = result.tk;
|
||
|
let enCryptMethodJDString = result.algo;
|
||
|
if (enCryptMethodJDString) {
|
||
|
this.enCryptMethodJD = new Function(`return ${enCryptMethodJDString}`)();
|
||
|
}
|
||
|
this.result = result
|
||
|
}
|
||
|
}
|
||
|
} catch (e) {
|
||
|
console.log(e)
|
||
|
} finally {
|
||
|
resolve(this.result);
|
||
|
}
|
||
|
})
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
module.exports = jxAlgo
|