ZZZ-Plugin/lib/mysapi.js
2024-07-08 22:17:31 +08:00

242 lines
6.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import md5 from 'md5';
import _ from 'lodash';
import crypto from 'crypto';
import ZZZApiTool from './mysapi/tool.js';
import MysApi from '../../genshin/model/mys/mysApi.js';
// const DEVICE_ID = randomString(32).toUpperCase()
const DEVICE_NAME = randomString(_.random(1, 10));
const game_region = [
'prod_gf_cn',
'prod_gf_cn',
'prod_gf_us',
'prod_gf_eu',
'prod_gf_jp',
'prod_gf_sg',
];
export default class MysZZZApi extends MysApi {
constructor(uid, cookie, option = {}) {
super(uid, cookie, option, true);
this.uid = uid;
this.server = this.getServer();
this.apiTool = new ZZZApiTool(uid, this.server);
if (typeof this.cookie != 'string' && this.cookie) {
let ck =
this.cookie[Object.keys(this.cookie).filter(k => this.cookie[k].ck)[0]];
this._device = ck?.device_id || ck?.device;
this.cookie = ck?.ck;
}
if (!this._device) {
this._device = crypto.randomUUID();
}
}
getServer() {
const _uid = this.uid.toString();
if (_uid.length < 10) {
return game_region[0]; // 官服
}
switch (_uid.slice(0, -8)) {
case '10':
return game_region[2]; // 美服
case '15':
return game_region[3]; // 欧服
case '13':
return game_region[4]; // 亚服
case '17':
return game_region[5]; // 港澳台服
}
}
getUrl(type, data = {}) {
data.deviceId = this._device;
let urlMap = this.apiTool.getUrlMap(data);
if (!urlMap[type]) return false;
let {
url,
query = '',
body = '',
noDs = false,
dsSalt = '',
} = urlMap[type];
if (query) url += `?${query}`;
if (body) body = JSON.stringify(body);
let headers = this.getHeaders(query, body);
if (data.deviceFp) {
headers['x-rpc-device_fp'] = data.deviceFp;
// 兼容喵崽
this._device_fp = { data: { device_fp: data.deviceFp } };
}
headers.cookie = this.cookie;
if (this._device) {
headers['x-rpc-device_id'] = this._device;
}
switch (dsSalt) {
case 'web': {
headers.DS = this.getDS2();
break;
}
default:
}
if (type === 'zzzAuthKey') {
let extra = {
DS: this.getDS2(),
Host: 'api-takumi.mihoyo.com',
};
headers = Object.assign(headers, extra);
} else {
headers.DS = this.getDs(query, body);
}
if (noDs) {
delete headers.DS;
if (this._device) {
body = JSON.parse(body);
body.device_id = this._device;
body = JSON.stringify(body);
}
}
return { url, headers, body };
}
getDs(q = '', b = '') {
let n = '';
if (['prod_gf_cn', 'prod_qd_cn'].includes(this.server)) {
n = 'xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs';
} else if (/prod_gf_/.test(this.server)) {
n = 'okr4obncj8bw5a65hbnn5oo6ixjc3l9w';
}
let t = Math.round(new Date().getTime() / 1000);
let r = Math.floor(Math.random() * 900000 + 100000);
let DS = md5(`salt=${n}&t=${t}&r=${r}&b=${b}&q=${q}`);
return `${t},${r},${DS}`;
}
getDS2() {
let t = Math.round(new Date().getTime() / 1000);
let r = randomString(6);
let sign = md5(`salt=BIPaooxbWZW02fGHZL1If26mYCljPgst&t=${t}&r=${r}`);
return `${t},${r},${sign}`;
}
getHeaders(query = '', body = '') {
const cn = {
app_version: '2.63.1',
User_Agent:
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.63.1',
client_type: '5',
Origin: 'https://webstatic.mihoyo.com',
X_Requested_With: 'com.mihoyo.hyperion',
Referer: 'https://webstatic.mihoyo.com/',
};
const os = {
app_version: '2.55.0',
User_Agent:
'Mozilla/5.0 (Linux; Android 11; J9110 Build/55.2.A.4.332; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/124.0.6367.179 Mobile Safari/537.36 miHoYoBBSOversea/2.55.0',
client_type: '2',
Origin: 'https://act.hoyolab.com',
X_Requested_With: 'com.mihoyo.hoyolab',
Referer: 'https://act.hoyolab.com/',
};
let client;
if (/official/.test(this.server)) {
client = os;
} else {
client = cn;
}
return {
'x-rpc-app_version': client.app_version,
'x-rpc-client_type': client.client_type,
'User-Agent': 'okhttp/4.8.0',
'x-rpc-sys_version': '12',
'x-rpc-client_type': '2',
'x-rpc-channel': 'mihoyo',
'User-Agent': client.User_Agent,
Referer: client.Referer,
DS: this.getDs(query, body),
Origin: client.Origin,
};
}
/**
* 校验状态码
* @param e 消息e
* @param res 请求返回
* @param type 请求类型 如 srNote
* @param data 查询请求的数据
* @returns {Promise<*|boolean>}
*/
async checkCode(e, res, type, data = {}) {
if (!res || !e) {
this.e.reply('米游社接口请求失败,暂时无法查询');
return false;
}
this.e = e;
this.e.isSr = true;
res.retcode = Number(res.retcode);
switch (res.retcode) {
case 0:
break;
case 10035:
case 1034: {
let handler = this.e.runtime?.handler || {};
// 如果有注册的mys.req.err调用
if (handler.has('mys.req.err')) {
logger.mark(
`[米游社zzz查询失败][uid:${this.uid}][qq:${this.userId}] 遇到验证码,尝试调用 Handler mys.req.err`
);
res =
(await handler.call('mys.req.err', this.e, {
mysApi: this,
type,
res,
data,
mysInfo: this,
})) || res;
}
if (!res || res?.retcode === 1034 || res?.retcode === 10035) {
logger.mark(
`[米游社zzz查询失败][uid:${this.uid}][qq:${this.userId}] 遇到验证码`
);
this.e.reply('米游社zzz查询遇到验证码请稍后再试');
}
break;
}
default:
if (/(登录|login)/i.test(res.message)) {
logger.mark(`[ck失效][uid:${this.uid}]`);
this.e.reply(`UID:${this.uid}米游社cookie已失效`);
} else {
this.e.reply(
`米游社接口报错,暂时无法查询:${res.message || 'error'}`
);
}
break;
}
if (res.retcode !== 0) {
logger.mark(
`[米游社zzz接口报错]${JSON.stringify(res)}uid${this.uid}`
);
}
return res;
}
}
export function randomString(length) {
let randomStr = '';
for (let i = 0; i < length; i++) {
randomStr += _.sample('abcdefghijklmnopqrstuvwxyz0123456789');
}
return randomStr;
}
export function generateSeed(length = 16) {
const characters = '0123456789abcdef';
let result = '';
for (let i = 0; i < length; i++) {
result += characters[Math.floor(Math.random() * characters.length)];
}
return result;
}