From 14f24bbd4d0e3367b1e3a54a2ce0caab7c91e0c8 Mon Sep 17 00:00:00 2001 From: bietiaop <1527109126@qq.com> Date: Fri, 16 Aug 2024 12:00:25 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=80=F0=9F=91=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/user.js | 86 ++++++++++++++++++++++++++++++++++++++++++++++ lib/mysapi.js | 59 +++++++++++++++++++++---------- lib/mysapi/tool.js | 21 ++++++++--- lib/plugin.js | 11 +++--- 4 files changed, 150 insertions(+), 27 deletions(-) create mode 100644 apps/user.js diff --git a/apps/user.js b/apps/user.js new file mode 100644 index 0000000..e0a8a42 --- /dev/null +++ b/apps/user.js @@ -0,0 +1,86 @@ +import { ZZZPlugin } from '../lib/plugin.js'; +import render from '../lib/render.js'; +import { rulePrefix } from '../lib/common.js'; +import { getPanelList, refreshPanel, getPanel } from '../lib/avatar.js'; +import settings from '../lib/settings.js'; +import _ from 'lodash'; + +export class Panel extends ZZZPlugin { + constructor() { + super({ + name: '[ZZZ-Plugin]User', + dsc: 'zzzuser', + event: 'message', + priority: _.get(settings.getConfig('priority'), 'user', 70), + rule: [ + { + reg: `${rulePrefix}绑定设备$`, + fnc: 'bindDevice', + }, + ], + }); + } + async bindDevice() { + const uid = await this.getUID(); + if (!uid) { + this.reply('未绑定UID'); + } + this.setContext('toBindDevice'); + await this.reply( + `为UID ${uid}绑定设备,请发送设备信息,或者发送“取消”取消绑定`, + false, + { at: true, recallMsg: 100 } + ); + } + async toBindDevice() { + const uid = await this.getUID(); + if (!uid) { + this.reply('未绑定UID'); + this.finish('toBindDevice'); + return false; + } + const msg = this.e.msg.trim(); + if (!msg) { + this.reply('请发送设备信息', false, { at: true, recallMsg: 100 }); + return false; + } + if (msg.includes('取消')) { + await this.reply('已取消', false, { at: true, recallMsg: 100 }); + this.finish('toBindDevice'); + return false; + } + try { + const info = JSON.parse(msg); + if (!info) { + this.reply('设备信息格式错误', false, { at: true, recallMsg: 100 }); + return false; + } + if ( + !'deviceName' in info || + !'deviceBoard' in info || + !'deviceModel' in info || + !'oaid' in info || + !'deviceFingerprint' in info || + !'deviceProduct' in info + ) { + this.reply('设备信息格式错误', false, { at: true, recallMsg: 100 }); + return false; + } + await redis.del(`ZZZ:DEVICE_FP:${uid}:FP`); + await redis.set(`ZZZ:DEVICE_FP:${uid}:BIND`, JSON.stringify(info)); + const { deviceFp } = await this.getAPI(); + if (!deviceFp) { + await this.reply('绑定设备失败'); + return false; + } + logger.debug(`[UID:${uid}]绑定设备成功,deviceFp:${deviceFp}`); + await this.reply('绑定设备成功', false, { at: true, recallMsg: 100 }); + } catch (error) { + this.reply('设备信息格式错误', false, { at: true, recallMsg: 100 }); + return false; + } finally { + this.finish('toBindDevice'); + return false; + } + } +} diff --git a/lib/mysapi.js b/lib/mysapi.js index 57b7a35..a2ed619 100644 --- a/lib/mysapi.js +++ b/lib/mysapi.js @@ -110,6 +110,16 @@ export default class MysZZZApi extends MysApi { if (this._device) { headers['x-rpc-device_id'] = this._device; } + if (data?.deviceInfo && data?.modelName) { + const deviceBrand = data.deviceInfo?.split('/')[0]; + try { + headers['x-rpc-device_name'] = `${deviceBrand} ${data.modelName}`; + headers['x-rpc-device_model'] = data.modelName; + headers['x-rpc-csm_source'] = 'myself'; + } catch (error) { + logger.error(`[ZZZ]设备信息解析失败:${error.message}`); + } + } // 写入DS switch (dsSalt) { case 'web': { @@ -136,7 +146,6 @@ export default class MysZZZApi extends MysApi { body = JSON.stringify(body); } } - logger.debug(`[mysapi]请求url:${url}`); // 返回请求参数 return { url, headers, body }; } @@ -237,20 +246,16 @@ export default class MysZZZApi extends MysApi { break; case 10102: if (res.message === 'Data is not public for the user') { - this.e.reply( - `\nUID:${this.uid},米游社数据未公开`, false, { at: this.userId } - ); + this.e.reply(`\nUID:${this.uid},米游社数据未公开`, false, { + at: this.userId, + }); } else { - this.e.reply( - `UID:${this.uid},请先去米游社绑定角色` - ); + this.e.reply(`UID:${this.uid},请先去米游社绑定角色`); } break; case 10041: case 5003: - this.e.reply( - `UID:${this.uid},米游社账号异常,暂时无法查询` - ); + this.e.reply(`UID:${this.uid},米游社账号异常,暂时无法查询`); break; case 10035: case 1034: { @@ -274,20 +279,14 @@ export default class MysZZZApi extends MysApi { logger.mark( `[米游社zzz查询失败][UID:${this.uid}][qq:${this.userId}] 遇到验证码` ); - this.e.reply( - '米游社zzz查询遇到验证码,请稍后再试' - ); + 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已失效` - ); + logger.mark(`[ck失效][UID:${this.uid}]`); + this.e.reply(`UID:${this.uid},米游社cookie已失效`); } else { this.e.reply( `米游社接口报错,暂时无法查询:${res.message || 'error'}` @@ -311,6 +310,28 @@ export default class MysZZZApi extends MysApi { * @param {boolean} cached */ async getFinalData(e, type, data = {}, cached = false) { + if (data.deviceFp) { + if (!data.headers) data.headers = {}; + data.headers['x-rpc-device_fp'] = data.deviceFp; + } + const uid = this.uid; + let bindInfo = await redis.get(`ZZZ:DEVICE_FP:${uid}:BIND`); + if (bindInfo) { + try { + bindInfo = JSON.parse(bindInfo); + data = { + ...data, + productName: bindInfo?.deviceProduct, + deviceType: bindInfo?.deviceName, + modelName: bindInfo?.deviceModel, + oaid: bindInfo?.oaid, + deviceInfo: bindInfo?.deviceFingerprint, + board: bindInfo?.deviceBoard, + }; + } catch (error) { + bindInfo = null; + } + } const result = await this.getData(type, data, cached); const _data = await this.checkCode(e, result, type, {}); if (!_data || _data.retcode !== 0) return false; diff --git a/lib/mysapi/tool.js b/lib/mysapi/tool.js index 1bdfcb1..1ff5500 100644 --- a/lib/mysapi/tool.js +++ b/lib/mysapi/tool.js @@ -1,4 +1,4 @@ -import { generateSeed } from '../../utils/data.js'; +import { generateSeed, randomString } from '../../utils/data.js'; import crypto from 'crypto'; /** * derived from miao-yunzai @@ -73,6 +73,15 @@ export default class ZZZApiTool { } getUrlMap = (data = {}) => { + const { + productName = 'J9110', + deviceType = 'J9110', + modelName = 'Sony', + oaid = 'e3ba65d61709d17074a306072a7c3a2ec70e6d374ca6d29eb6b1b965cbb68e23', + deviceInfo = `Sony\/J9110\/J9110:11\/55.2.A.4.332\/055002A004033203408384484:user\/release-keys`, + board = 'msmnile', + } = data; + const deviceBrand = deviceInfo.split('/')[0]; let urlMap = { zzz: { ...(['prod_gf_cn'].includes(this.server) @@ -82,9 +91,13 @@ export default class ZZZApiTool { body: { seed_id: `${generateSeed(13)}`, device_id: data.deviceId, - platform: '1', + platform: '2', seed_time: new Date().getTime() + '', - ext_fields: `{"romRemain":"16357","romCapacity":"121947","osVersion":"15.7.1","ramCapacity":"3662","ramRemain":"62","appUpdateTimeDiff":"1722253089969","isJailBreak":"0","cpuCores":"6","magnetometer":"-205.693817x20.642471x-103.278427","vendor":"中国电信","networkType":"WIFI","gyroscope":"0.371554x0.804200x-0.526751","appMemory":"82","packageName":"com.miHoYo.mhybbs","model":"iPhone13,2","hasVpn":"1","appInstallTimeDiff":"1722253055560","screenBrightness":"0.063","cpuType":"CPU_TYPE_ARM64","chargeStatus":"1","packageVersion":"2.20.1","IDFV":"${data.deviceId.toUpperCase()}","deviceName":"navel","buildTime":"1719312801323","accelerometer":"0.044586x-0.842255x-0.624100","screenSize":"390×844","proxyStatus":"1","isPushEnabled":"0","isSimInserted":"1","batteryStatus":"46"}`, + ext_fields: `{"cpuType":"arm64-v8a","romCapacity":"512","productName":"${productName}","romRemain":"422","manufacturer":"${deviceBrand}","appMemory":"512","hostname":"dg02-pool03-kvm87","screenSize":"1264x2640","osVersion":"13","aaid":"${randomString( + 64 + )}","vendor":"中国联通","accelerometer":"0.44027936x7.256833x6.422336","buildTags":"release-keys","model":"${modelName}","brand":"XiaoMi","oaid":"${oaid}","hardware":"qcom","deviceType":"${deviceType}","devId":"REL","serialNumber":"unknown","buildTime":"1687848011000","buildUser":"root","ramCapacity":"469679","magnetometer":"20.081251x-27.487501x2.1937501","display":"${modelName}_13.1.0.181(CN01)","ramRemain":"215344","deviceInfo":"${deviceInfo}","gyroscope":"0.030226856x0.014647375x0.010652636","vaid":"${randomString( + 64 + )}","buildType":"user","sdkVersion":"33","board":"${board}"}`, bbs_device_id: data.deviceId, app_name: 'bbs_cn', device_fp: '38d7fc717dc22', @@ -101,7 +114,7 @@ export default class ZZZApiTool { hoyolab_device_id: `${this.uuid}`, platform: '2', seed_time: new Date().getTime() + '', - ext_fields: `{"proxyStatus":1,"isRoot":1,"romCapacity":"512","deviceName":"Xperia 1","productName":"J9110","romRemain":"483","hostname":"BuildHost","screenSize":"1096x2434","isTablet":0,"model":"J9110","brand":"Sony","hardware":"qcom","deviceType":"J9110","devId":"REL","serialNumber":"unknown","sdCapacity":107433,"buildTime":"1633631032000","buildUser":"BuildUser","simState":1,"ramRemain":"98076","appUpdateTimeDiff":1716545162858,"deviceInfo":"Sony\/J9110\/J9110:11\/55.2.A.4.332\/055002A004033203408384484:user\/release-keys","buildType":"user","sdkVersion":"30","ui_mode":"UI_MODE_TYPE_NORMAL","isMockLocation":0,"cpuType":"arm64-v8a","isAirMode":0,"ringMode":2,"app_set_id":"${this.uuid}","chargeStatus":1,"manufacturer":"Sony","emulatorStatus":0,"appMemory":"512","adid":"${this.uuid}","osVersion":"11","vendor":"unknown","accelerometer":"-0.9233304x7.574181x6.472585","sdRemain":97931,"buildTags":"release-keys","packageName":"com.mihoyo.hoyolab","networkType":"WiFi","debugStatus":1,"ramCapacity":"107433","magnetometer":"-9.075001x-27.300001x-3.3000002","display":"55.2.A.4.332","appInstallTimeDiff":1716489549794,"packageVersion":"","gyroscope":"0.027029991x-0.04459185x0.032222193","batteryStatus":45,"hasKeyboard":0,"board":"msmnile"}`, + ext_fields: `{"proxyStatus":1,"isRoot":1,"romCapacity":"512","deviceName":"Xperia 1","productName":"${productName}","romRemain":"483","hostname":"BuildHost","screenSize":"1096x2434","isTablet":0,"model":"${modelName}","brand":"${deviceBrand}","hardware":"qcom","deviceType":"${deviceType}","oaid":"${oaid}","devId":"REL","serialNumber":"unknown","sdCapacity":107433,"buildTime":"1633631032000","buildUser":"BuildUser","simState":1,"ramRemain":"98076","appUpdateTimeDiff":1716545162858,"deviceInfo":"${deviceInfo}","buildType":"user","sdkVersion":"30","ui_mode":"UI_MODE_TYPE_NORMAL","isMockLocation":0,"cpuType":"arm64-v8a","isAirMode":0,"ringMode":2,"app_set_id":"${this.uuid}","chargeStatus":1,"manufacturer":"${deviceBrand}","emulatorStatus":0,"appMemory":"512","adid":"${this.uuid}","osVersion":"11","vendor":"unknown","accelerometer":"-0.9233304x7.574181x6.472585","sdRemain":97931,"buildTags":"release-keys","packageName":"com.mihoyo.hoyolab","networkType":"WiFi","debugStatus":1,"ramCapacity":"107433","magnetometer":"-9.075001x-27.300001x-3.3000002","display":"${modelName}","appInstallTimeDiff":1716489549794,"packageVersion":"","gyroscope":"0.027029991x-0.04459185x0.032222193","batteryStatus":45,"hasKeyboard":0,"board":"${board}"}`, app_name: 'bbs_oversea', device_fp: '38d7f2352506c', }, diff --git a/lib/plugin.js b/lib/plugin.js index 41cd574..f423289 100644 --- a/lib/plugin.js +++ b/lib/plugin.js @@ -56,7 +56,7 @@ export class ZZZPlugin extends plugin { // 创建米游社 API 对象 const api = new MysZZZApi(uid, ck); // 获取设备指纹 - let deviceFp = await redis.get(`ZZZ:DEVICE_FP:${uid}`); + let deviceFp = await redis.get(`ZZZ:DEVICE_FP:${uid}:FP`); if (!deviceFp) { const sdk = api.getUrl('getFp'); const res = await fetch(sdk.url, { @@ -65,9 +65,10 @@ export class ZZZPlugin extends plugin { body: sdk.body, }); const fpRes = await res.json(); + logger.debug(`[米游社][设备指纹]${JSON.stringify(fpRes)}`); deviceFp = fpRes?.data?.device_fp; if (deviceFp) { - await redis.set(`ZZZ:DEVICE_FP:${uid}`, deviceFp, { + await redis.set(`ZZZ:DEVICE_FP:${uid}:FP`, deviceFp, { EX: 86400 * 7, }); } @@ -86,10 +87,12 @@ export class ZZZPlugin extends plugin { */ async getPlayerInfo() { // 获取 米游社 API - const { api, uid } = await this.getAPI(); + const { api, uid, deviceFp } = await this.getAPI(); if (!api) return false; // 获取用户信息 - let userData = await api.getFinalData(this.e, 'zzzUser'); + let userData = await api.getFinalData(this.e, 'zzzUser', { + deviceFp, + }); if (!userData) return false; // 取第一个用户信息 userData =