-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
298 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |