Skip to content

Commit

Permalink
🌱 成功获取扫码登录返回 tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
BTMuli committed Aug 31, 2023
1 parent cf691d8 commit a3c1442
Show file tree
Hide file tree
Showing 6 changed files with 298 additions and 1 deletion.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@
"js-md5": "^0.7.3",
"pinia": "^2.1.6",
"pinia-plugin-persistedstate": "^3.2.0",
"qrcode.vue": "^3.4.1",
"tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql#v1",
"uuid": "^9.0.0",
"vue": "^3.3.4",
"vue-echarts": "^6.6.1",
"vue-json-viewer": "^3.0.4",
Expand Down
19 changes: 19 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"https://bbs.mihoyo.com/*",
"https://hk4e-api.mihoyo.com/*",
"https://passport-api.mihoyo.com/*",
"https://passport-api.miyoushe.com/*",
"https://passport-api-v4.mihoyo.com/*",
"https://act-webstatic.mihoyo.com/*",
"https://sdk-webstatic.mihoyo.com/*",
Expand Down
53 changes: 52 additions & 1 deletion src/pages/common/Test.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,57 @@
<template>
<div>
<h1>Test</h1>
<div class="btn-list">
<v-btn @click="renderQr">渲染二维码</v-btn>
<v-btn @click="getData">获取数据</v-btn>
</div>
<div class="qr-container">
<qrcode-vue :value="content" :size="size" level="H" render-as="svg" />
</div>
</div>
</template>
<script lang="ts" setup></script>
<script lang="ts" setup>
// vue
import { ref } from "vue";
import QrcodeVue from "qrcode.vue";
import showSnackbar from "../../components/func/snackbar";
// utils
import { getLoginQr, getLoginStatus } from "../../plugins/Mys/utils/doWebLogin";
const content = ref<string>("qrcode");
const size = ref<number>(300);
const ticket = ref<string>("");
async function renderQr(): Promise<void> {
const res = await getLoginQr();
if ("retcode" in res) {
showSnackbar({
text: `[${res.retcode}] ${res.message}`,
color: "error",
});
return;
}
ticket.value = res.ticket;
content.value = res.url;
}
async function getData(): Promise<void> {
const res = await getLoginStatus(ticket.value);
if ("retcode" in res) {
showSnackbar({
text: `[${res.retcode}] ${res.message}`,
color: "error",
});
return;
}
console.log(res);
}
</script>
<style lang="css" scoped>
.btn-list {
display: flex;
justify-content: flex-start;
margin-bottom: 20px;
gap: 10px;
}
</style>
134 changes: 134 additions & 0 deletions src/plugins/Mys/types/WebLogin.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/**
* @file plugins Mys types WebLogin.d.ts
* @description Mys 插件 Web 登录类型定义文件
* @author BTMuli <[email protected]>
* @since Beta v0.3.0
*/

/**
* @description Mys 插件 Web 登录类型
* @since Beta v0.3.0
* @namespace WebLogin
* @return WebLogin
*/
declare namespace TGApp.Plugins.Mys.WebLogin {
/**
* @description 获取登录二维码返回数据
* @since Beta v0.3.0
* @interface GetLoginQrResponse
* @extends TGApp.Plugins.Mys.Base.Response
* @property {GetLoginQrData} data 数据
* @return GetLoginQrResponse
*/
export interface GetLoginQrResponse extends TGApp.Plugins.Mys.Base.Response {
data: GetLoginQrData;
}

/**
* @description 获取登录二维码返回数据
* @since Beta v0.3.0
* @interface GetLoginQrData
* @property {string} ticket 二维码票据
* @property {string} url 二维码链接
* @return GetLoginQrData
*/
export interface GetLoginQrData {
ticket: string;
url: string;
}

/**
* @description 获取登录状态返回数据
* @since Beta v0.3.0
* @interface GetLoginStatusResponse
* @extends TGApp.Plugins.Mys.Base.Response
* @property {GetLoginStatusData} data 数据
* @return GetLoginStatusResponse
*/
export interface GetLoginStatusResponse extends TGApp.Plugins.Mys.Base.Response {
data: GetLoginStatusData;
}

/**
* @description 获取登录状态返回数据
* @since Beta v0.3.0
* @interface GetLoginStatusData
* @property {string} app_id 应用 ID
* @property {number} client_type 客户端类型
* @property {string} created_at 创建时间
* @property {boolean} need_realperson 是否需要人机验证
* @property {RealNameInfo} realname_info 实名信息
* @property {string} scanned_at 扫码时间
* @property {string} status 状态
* @property {unknown[]} tokens 令牌
* @property {UserInfo} user_info 用户信息
* @return GetLoginStatusData
*/
export interface GetLoginStatusData {
app_id: string;
client_type: number;
created_at: string;
need_realperson: boolean;
realname_info: RealNameInfo;
scanned_at: string;
status: string;
tokens: unknown[];
user_info: UserInfo;
}

/**
* @description 实名信息
* @since Beta v0.3.0
* @interface RealNameInfo
* @property {string} action_ticket 动作票据
* @property {string} action_type 动作类型
* @property {boolean} required 是否必须
* @return RealNameInfo
*/
interface RealNameInfo {
action_ticket: string;
action_type: string;
required: boolean;
}

/**
* @description 用户信息
* @since Beta v0.3.0
* @interface UserInfo
* @property {string} account_name 账户名
* @property {string} aid 账户 ID
* @property {string} area_code 区域代码
* @property {string} country 国家
* @property {string} email 邮箱 // 为加密后的邮箱包含 * 号
* @property {string} identity_code 身份证号 // 为加密后的身份证号包含 * 号
* @property {number} is_email_verify 是否邮箱验证 // 1 为已验证
* @property {unknown[]} links 链接
* @property {string} mid 用户 ID
* @property {string} mobile 手机号 // 为加密后的手机号包含 * 号
* @property {string} realname 真实姓名 // 为加密后的真实姓名包含 * 号
* @property {string} rebind_area_code 重新绑定区域代码
* @property {string} rebind_mobile 重新绑定手机号
* @property {string} rebind_mobile_time 重新绑定手机号时间
* @property {string} safe_area_code 安全区域代码
* @property {string} safe_mobile 安全手机号
* @return UserInfo
*/
interface UserInfo {
account_name: string;
aid: string;
area_code: string;
country: string;
email: string;
identity_code: string;
is_email_verify: number;
links: unknown[];
mid: string;
mobile: string;
realname: string;
rebind_area_code: string;
rebind_mobile: string;
rebind_mobile_time: string;
safe_area_code: string;
safe_mobile: string;
}
}
90 changes: 90 additions & 0 deletions src/plugins/Mys/utils/doWebLogin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* @file plugins Mys utils getLoginQr
* @description 获取登录二维码
* @author BTMuli <[email protected]>
* @since Beta v0.3.0
*/

// tauri
import { http } from "@tauri-apps/api";

const uuid = crypto.randomUUID();

const headers: Record<string, string> = {
Accept: "application/json, text/plain, */*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9",
Connection: "keep-alive",
Origin: "https://user.miyoushe.com",
Referer: "https://user.miyoushe.com/",
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
"x-rpc-app_id": "bll8iq97cem8",
"x-rpc-client_type": "4",
"x-rpc-device_model": "Chrome 116.0.0.0",
"x-rpc-device_name": "Chrome",
"x-rpc-device_os": "Windows 10 64-bit",
"x-rpc-game_biz": "bbs_cn",
"x-rpc-mi_referrer":
"https://user.miyoushe.com/login-platform/index.html?app_id=bll8iq97cem8&app_version=2.58.0&theme=&token_type=4&game_biz=bbs_cn&message_origin=https%253A%252F%252Fwww.miyoushe.com&succ_back_type=message%253Alogin-platform%253Alogin-success&fail_back_type=message%253Alogin-platform%253Alogin-fail&sync_login_status=popup&ux_mode=popup&iframe_level=1&ap_mps=1#/login/qr",
"x-rpc-sdk_version": "2.17.0",
"X-Rpc-Device_fp": "",
"X-Rpc-Device_id": uuid,
};

/**
* @description 获取登录二维码
* @since Beta v0.3.0
* @returns {Promise<TGApp.Plugins.Mys.WebLogin.GetLoginQrData|TGApp.Plugins.Mys.Base.Response>}
*/
export async function getLoginQr(): Promise<
TGApp.Plugins.Mys.WebLogin.GetLoginQrData | TGApp.Plugins.Mys.Base.Response
> {
const url = "https://passport-api.miyoushe.com/account/ma-cn-passport/web/createQRLogin";
return await http
.fetch<TGApp.Plugins.Mys.WebLogin.GetLoginQrResponse>(url, {
method: "POST",
headers,
body: http.Body.json({}),
})
.then((res) => {
if (res.data.retcode === 0) {
return res.data.data;
} else {
return res.data;
}
});
}

/**
* @description 获取登录状态
* @since Beta v0.3.0
* @param {string} ticket 二维码票据
* @returns {Promise<Record<string, string[]>}
*/
export async function getLoginStatus(
ticket: string,
): Promise<TGApp.Plugins.Mys.WebLogin.GetLoginStatusResponse | Record<string, string>> {
const url = "https://passport-api.miyoushe.com/account/ma-cn-passport/web/queryQRLoginStatus";
const resp = await http.fetch<TGApp.Plugins.Mys.WebLogin.GetLoginStatusResponse>(url, {
method: "POST",
headers,
body: http.Body.json({ ticket }),
});
const data = resp.data;
if (data.retcode !== 0) return resp.data;
if (data.data.status === "Created" || data.data.status === "Scanned") {
await new Promise((resolve) => setTimeout(resolve, 5000));
return await getLoginStatus(ticket);
}
if (data.data.status === "Confirmed") {
const cookieList = resp.rawHeaders["set-cookie"].map((cookie) => cookie.split(";")[0]);
const cookieRecord: Record<string, string> = {};
cookieList.forEach((cookie) => {
const [key, value] = cookie.split("=");
cookieRecord[key] = value;
});
return cookieRecord;
}
return resp.data;
}

0 comments on commit a3c1442

Please sign in to comment.