From e3e5b757e4a3948147711c8b14e2a2e0c551d726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9B=AE=E6=A3=83?= Date: Fri, 26 Jul 2024 18:02:58 +0800 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=E9=87=8D=E6=9E=84=20http?= =?UTF-8?q?=20req=EF=BC=8C=E6=8D=95=E8=8E=B7aigis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 8 ++++ src/plugins/Mys/request/doCaptchaLogin.ts | 51 ++++++++++++++++------- src/utils/TGHttp.ts | 27 ++++++++---- 4 files changed, 66 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 677ff7c6..126698d3 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "geetest": "^4.1.2", "html2canvas": "^1.4.1", "js-md5": "^0.8.3", + "jsencrypt": "^3.3.2", "pinia": "^2.1.7", "pinia-plugin-persistedstate": "^3.2.1", "qrcode.vue": "^3.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d7d2f90b..adde4cf0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -65,6 +65,9 @@ importers: js-md5: specifier: ^0.8.3 version: 0.8.3 + jsencrypt: + specifier: ^3.3.2 + version: 3.3.2 pinia: specifier: ^2.1.7 version: 2.1.7(typescript@5.5.3)(vue@3.4.32(typescript@5.5.3)) @@ -2202,6 +2205,9 @@ packages: jsbn@0.1.1: resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + jsencrypt@3.3.2: + resolution: {integrity: sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==} + jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} @@ -5497,6 +5503,8 @@ snapshots: jsbn@0.1.1: {} + jsencrypt@3.3.2: {} + jsesc@2.5.2: {} json-buffer@3.0.1: {} diff --git a/src/plugins/Mys/request/doCaptchaLogin.ts b/src/plugins/Mys/request/doCaptchaLogin.ts index 48554b5b..af9cceee 100644 --- a/src/plugins/Mys/request/doCaptchaLogin.ts +++ b/src/plugins/Mys/request/doCaptchaLogin.ts @@ -4,17 +4,20 @@ * @since Beta v0.5.1 */ -import { publicEncrypt } from "node:crypto"; +import { JSEncrypt } from "jsencrypt"; +import showSnackbar from "../../../components/func/snackbar.js"; import TGHttp from "../../../utils/TGHttp.js"; import { getDeviceInfo } from "../../../utils/toolFunc.js"; import TGConstant from "../../../web/constant/TGConstant.js"; -const PUB_KEY = `-----BEGIN PUBLIC KEY----- +const PUB_KEY_STR = `-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDvekdPMHN3AYhm/vktJT+YJr7cI5DcsNKqdsx5DZX0gDuWFuIjzdwButrIYPNmRJ1G8ybDIF7oDW2eEpm5sMbL9zs 9ExXCdvqrn51qELbqj0XxtMTIpaCHFSI50PfPpTFV9Xt/hmyVwokoOXFlAEgCn+Q CgGs52bFoYMtyi+xEQIDAQAB -----END PUBLIC KEY-----`; +const encrypt = new JSEncrypt(); +encrypt.setPublicKey(PUB_KEY_STR); /** * @description rsa 加密 @@ -23,8 +26,15 @@ CgGs52bFoYMtyi+xEQIDAQAB * @returns {string} 加密后数据 */ function rsaEncrypt(data: string): string { - const buffer = Buffer.from(data); - return publicEncrypt(PUB_KEY, buffer).toString("base64"); + const res = encrypt.encrypt(data.toString()); + if (res === false) { + showSnackbar({ + text: "RSA 加密失败", + color: "error", + }); + return ""; + } + return res; } /** @@ -36,14 +46,14 @@ function rsaEncrypt(data: string): string { */ export async function getCaptcha( phone: string, -): Promise { +): Promise { const url = "https://passport-api.mihoyo.com/account/ma-cn-verifier/verifier/createLoginCaptcha"; const device_fp = getDeviceInfo("device_fp"); const device_name = getDeviceInfo("device_name"); const device_id = getDeviceInfo("device_id"); const device_model = getDeviceInfo("product"); const body = { area_code: rsaEncrypt("+86"), mobile: rsaEncrypt(phone) }; - const header = { + const header: Record = { "x-rpc-aigis": "", "x-rpc-app_version": TGConstant.BBS.VERSION, "x-rpc-client_type": "2", @@ -61,13 +71,24 @@ export async function getCaptcha( console.log("getCaptcha body: ", body); const resp = await TGHttp< TGApp.Plugins.Mys.CaptchaLogin.CaptchaResponse | TGApp.BBS.Response.Base - >(url, { - method: "POST", - headers: header, - body: JSON.stringify(body), - }); - if (resp.retcode !== 0) return resp; - return resp.data; + >( + url, + { + method: "POST", + headers: header, + body: JSON.stringify(body), + }, + true, + ); + const data = await resp.data; + if (data.retcode !== 0) { + return { + retcode: data.retcode, + message: data.message, + data: resp.resp.headers.get("x-rpc-aigis"), + }; + } + return data.data; } /** @@ -76,12 +97,14 @@ export async function getCaptcha( * @param {string} phone - 手机号 * @param {string} captcha - 验证码 * @param {string} action_type - 操作类型 + * @param {string} [aigis] - 验证数据 * @returns {Promise} */ export async function doCaptchaLogin( phone: string, captcha: string, action_type: string, + aigis?: string, ): Promise { const url = "https://passport-api.mihoyo.com/account/ma-cn-passport/app/loginByMobileCaptcha"; const device_fp = getDeviceInfo("device_fp"); @@ -95,7 +118,7 @@ export async function doCaptchaLogin( captcha, }; const header = { - "x-rpc-aigis": "", + "x-rpc-aigis": aigis || "", "x-rpc-app_version": TGConstant.BBS.VERSION, "x-rpc-client_type": "2", "x-rpc-app_id": TGConstant.BBS.APP_ID, diff --git a/src/utils/TGHttp.ts b/src/utils/TGHttp.ts index 44bdfda9..ad5c84fd 100644 --- a/src/utils/TGHttp.ts +++ b/src/utils/TGHttp.ts @@ -1,14 +1,14 @@ /** * @file utils/TGHttp.ts * @description 封装HTTP请求 - * @since Beta v0.5.0 + * @since Beta v0.5.1 */ import { fetch } from "@tauri-apps/plugin-http"; /** * @description 请求参数 - * @since Beta v0.5.0 + * @since Beta v0.5.1 * @property {"GET"|"POST"} method 请求方法 * @property {Record} headers 请求头 * @property {Record} query 请求参数 @@ -26,13 +26,23 @@ type TGHttpParams = { /** * @description 发送请求 - * @since Beta v0.5.0 + * @since Beta v0.5.1 * @template T * @param {string} url 请求地址 * @param {TGHttpParams} options 请求参数 - * @returns {Promise} + * @returns {Promise} 请求结果 */ -async function TGHttp(url: string, options: TGHttpParams): Promise { +async function TGHttp(url: string, options: TGHttpParams): Promise; +async function TGHttp( + url: string, + options: TGHttpParams, + fullResponse: true, +): Promise<{ data: Promise; resp: Response }>; +async function TGHttp( + url: string, + options: TGHttpParams, + fullResponse?: true, +): Promise; resp: Response }> { const httpHeaders = new Headers(); if (options.headers) { for (const key in options.headers) { @@ -55,8 +65,11 @@ async function TGHttp(url: string, options: TGHttpParams): Promise { return await fetch(url, fetchOptions) .then((res) => { if (res.ok) { - if (options.isBlob) return res.arrayBuffer(); - return res.json(); + const data = options.isBlob ? res.blob() : res.json(); + if (fullResponse) { + return { data, resp: res }; + } + return data; } throw new Error(`HTTP error! status: ${res.status}`); })