mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-12 09:18:14 +08:00
🌱 完成相关请求,待测试 #47
This commit is contained in:
136
src/components/overlay/to-geetest.vue
Normal file
136
src/components/overlay/to-geetest.vue
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<template>
|
||||||
|
<TOverlay v-model="visible" hide blur-val="20px">
|
||||||
|
<div class="tog-box">
|
||||||
|
<div class="tog-top">
|
||||||
|
<div class="tog-title">请完成如下极验测试</div>
|
||||||
|
</div>
|
||||||
|
<div id="verify" class="tog-mid">
|
||||||
|
<div id="geetest"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TOverlay>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
// vue
|
||||||
|
import { computed, watch } from "vue";
|
||||||
|
import showSnackbar from "../func/snackbar";
|
||||||
|
import TOverlay from "../main/t-overlay.vue";
|
||||||
|
// store
|
||||||
|
import { useUserStore } from "../../store/modules/user";
|
||||||
|
// utils
|
||||||
|
import TGRequest from "../../web/request/TGRequest";
|
||||||
|
|
||||||
|
interface ToGeetestProps {
|
||||||
|
modelValue: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToGeetestEmits = (e: "update:modelValue", value: boolean) => void;
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<ToGeetestProps>(), {
|
||||||
|
modelValue: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emits = defineEmits<ToGeetestEmits>();
|
||||||
|
|
||||||
|
const visible = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (value) => {
|
||||||
|
emits("update:modelValue", value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(visible, async (value) => {
|
||||||
|
if (value) {
|
||||||
|
await getChallenge();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
// 获取极验验证码
|
||||||
|
async function getChallenge(): Promise<void> {
|
||||||
|
const cookie = userStore.getCookieGroup3();
|
||||||
|
const res = await TGRequest.User.verification.get(cookie.ltoken, cookie.ltuid);
|
||||||
|
if ("retcode" in res) {
|
||||||
|
showSnackbar({
|
||||||
|
text: res.message,
|
||||||
|
color: "error",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// @ts-expect-error Cannot find name 'initGeetest'.ts(2304)
|
||||||
|
initGeetest(
|
||||||
|
{
|
||||||
|
gt: res.gt,
|
||||||
|
challenge: res.challenge,
|
||||||
|
offline: false,
|
||||||
|
new_captcha: true,
|
||||||
|
|
||||||
|
product: "custom", // 产品形式,包括:float,popup, bind
|
||||||
|
area: "#verify", // 选择验证码展示的位置
|
||||||
|
width: "250px",
|
||||||
|
},
|
||||||
|
(captchaObj: TGApp.BBS.Geetest.GeetestCaptcha) => {
|
||||||
|
captchaObj.appendTo("#geetest");
|
||||||
|
captchaObj
|
||||||
|
.onReady(() => {
|
||||||
|
console.log("ready");
|
||||||
|
})
|
||||||
|
.onSuccess(() => {
|
||||||
|
const validate = captchaObj.getValidate();
|
||||||
|
(async () => {
|
||||||
|
await doVerify(validate);
|
||||||
|
})().catch(() => {}); // 防止报错
|
||||||
|
})
|
||||||
|
.onError(() => {
|
||||||
|
console.log("error");
|
||||||
|
})
|
||||||
|
.onClose(() => {
|
||||||
|
console.log("close");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doVerify(data: TGApp.BBS.Geetest.GeetestValidate): Promise<void> {
|
||||||
|
await TGRequest.User.verification.verify(userStore.cookie, data);
|
||||||
|
emits("update:modelValue", false);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.tog-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: var(--box-bg-1);
|
||||||
|
color: var(--app-page-content);
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tog-top {
|
||||||
|
border-bottom: 1px solid var(--common-shadow-4);
|
||||||
|
font-family: var(--font-title);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tog-title {
|
||||||
|
color: var(--common-text-title);
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tog-mid {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background: var(--box-bg-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#verify {
|
||||||
|
width: 256px;
|
||||||
|
height: 320px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -13,9 +13,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<h1>极验测试</h1>
|
||||||
|
<div class="btn-list">
|
||||||
|
<v-btn class="test-btn" @click="getGC">获取极验</v-btn>
|
||||||
|
</div>
|
||||||
|
<to-geetest v-model="visible"></to-geetest>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup></script>
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import ToGeetest from "../../components/overlay/to-geetest.vue";
|
||||||
|
|
||||||
|
const visible = ref<boolean>(false);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
visible.value = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
function getGC(): void {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.btn-list {
|
.btn-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
61
src/types/BBS/Geetest.d.ts
vendored
61
src/types/BBS/Geetest.d.ts
vendored
@@ -47,4 +47,65 @@ declare namespace TGApp.BBS.Geetest {
|
|||||||
challenge: string;
|
challenge: string;
|
||||||
validate: string;
|
validate: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 极验验证的请求方法-请求参数
|
||||||
|
* @since Beta v0.3.3
|
||||||
|
* @interface InitGeetestParams
|
||||||
|
* @property {string} gt - 极验验证 gt
|
||||||
|
* @property {string} challenge - 极验验证 challenge
|
||||||
|
* @property {boolean} offline - 极验验证 offline
|
||||||
|
* @property {boolean} new_captcha - 极验验证 new_captcha
|
||||||
|
* @property {string} product - 极验验证 product
|
||||||
|
* @property {string} width - 极验验证 width
|
||||||
|
* @property {boolean} https - 极验验证 https
|
||||||
|
* @return InitGeetestParams
|
||||||
|
*/
|
||||||
|
export interface InitGeetestParams {
|
||||||
|
gt: string;
|
||||||
|
challenge: string;
|
||||||
|
offline: boolean;
|
||||||
|
new_captcha: boolean;
|
||||||
|
product: string;
|
||||||
|
width: string;
|
||||||
|
https: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Geetest 插件 captchaObj
|
||||||
|
* @since Beta v0.3.3
|
||||||
|
* @todo 完善
|
||||||
|
* @interface GeetestCaptcha
|
||||||
|
* @property {string} getValidate
|
||||||
|
* @property {Function} onReady
|
||||||
|
* @property {Function} onRefresh
|
||||||
|
* @property {Function} onSuccess
|
||||||
|
* @property {Function} onError
|
||||||
|
* @property {Function} onClose
|
||||||
|
* @return GeetestCaptcha
|
||||||
|
*/
|
||||||
|
export interface GeetestCaptcha {
|
||||||
|
appendTo: (selector: string) => void;
|
||||||
|
getValidate: () => GeetestValidate;
|
||||||
|
onReady: (callback: () => void) => GeetestCaptcha;
|
||||||
|
onRefresh: (callback: () => void) => GeetestCaptcha;
|
||||||
|
onSuccess: (callback: () => void) => GeetestCaptcha;
|
||||||
|
onError: (callback: () => void) => GeetestCaptcha;
|
||||||
|
onClose: (callback: () => void) => GeetestCaptcha;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Geetest 插件 validate
|
||||||
|
* @since Beta v0.3.3
|
||||||
|
* @interface GeetestValidate
|
||||||
|
* @property {string} geetest_challenge
|
||||||
|
* @property {string} geetest_validate
|
||||||
|
* @property {string} geetest_seccode
|
||||||
|
* @return GeetestValidate
|
||||||
|
*/
|
||||||
|
export interface GeetestValidate {
|
||||||
|
geetest_challenge: string;
|
||||||
|
geetest_validate: string;
|
||||||
|
geetest_seccode: string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
89
src/types/Plugins/Geetest.d.ts
vendored
89
src/types/Plugins/Geetest.d.ts
vendored
@@ -1,89 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file src types Plugins Geetest.d.ts
|
|
||||||
* @description Geetest 插件类型声明文件
|
|
||||||
* @author BTMuli <bt-muli@outlook.com>
|
|
||||||
* @since 3.0.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 因为引入 gt.js,其 initGeetest 挂载到 window 上,所以需要声明 window
|
|
||||||
* @since 3.0.0
|
|
||||||
* @interface window
|
|
||||||
* @return window
|
|
||||||
*/
|
|
||||||
type window = Window & typeof globalThis;
|
|
||||||
|
|
||||||
globalThis.window = globalThis.window || globalThis;
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
initGeetest: InitGeetest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description Geetest 插件初始化函数
|
|
||||||
* @since 3.0.0
|
|
||||||
* @interface InitGeetest
|
|
||||||
* @return InitGeetest
|
|
||||||
*/
|
|
||||||
export type InitGeetest = (
|
|
||||||
initGeetestOptions: InitGeetestOptions,
|
|
||||||
initGeetestCallback: InitGeetestCallback,
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description Geetest 插件初始化函数参数
|
|
||||||
* @since 3.0.0
|
|
||||||
* @todo 完善
|
|
||||||
* @interface InitGeetestOptions
|
|
||||||
* @property {string} gt Geetest ID
|
|
||||||
* @property {string} challenge Geetest challenge
|
|
||||||
* @property {boolean} offline Geetest offline
|
|
||||||
* @property {boolean} new_captcha Geetest new_captcha
|
|
||||||
* @property {string} product Geetest product
|
|
||||||
* @property {string} width Geetest width
|
|
||||||
* @property {boolean} https Geetest https
|
|
||||||
* @return InitGeetestOptions
|
|
||||||
*/
|
|
||||||
export interface InitGeetestOptions {
|
|
||||||
gt: string;
|
|
||||||
challenge: string;
|
|
||||||
offline: boolean;
|
|
||||||
new_captcha: boolean;
|
|
||||||
product: string;
|
|
||||||
width: string;
|
|
||||||
https: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description Geetest 插件初始化函数回调
|
|
||||||
* @since 3.0.0
|
|
||||||
* @todo 完善
|
|
||||||
* @interface InitGeetestCallback
|
|
||||||
* @return InitGeetestCallback
|
|
||||||
*/
|
|
||||||
export type InitGeetestCallback = (captchaObj: GeetestCaptcha) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description Geetest 插件 captchaObj
|
|
||||||
* @since 3.0.0
|
|
||||||
* @todo 完善
|
|
||||||
* @interface GeetestCaptcha
|
|
||||||
* @property {string} getValidate
|
|
||||||
* @property {Function} onReady
|
|
||||||
* @property {Function} onRefresh
|
|
||||||
* @property {Function} onSuccess
|
|
||||||
* @property {Function} onError
|
|
||||||
* @property {Function} onClose
|
|
||||||
* @return GeetestCaptcha
|
|
||||||
*/
|
|
||||||
export interface GeetestCaptcha {
|
|
||||||
appendTo: (selector: string) => void;
|
|
||||||
getValidate: () => string;
|
|
||||||
onReady: (callback: () => void) => void;
|
|
||||||
onRefresh: (callback: () => void) => void;
|
|
||||||
onSuccess: (callback: () => void) => void;
|
|
||||||
onError: (callback: () => void) => void;
|
|
||||||
onClose: (callback: () => void) => void;
|
|
||||||
}
|
|
||||||
@@ -15,12 +15,13 @@ import { getGameAccountsByCookie, getGameAccountsBySToken } from "./getGameAccou
|
|||||||
import { getGameRecord } from "./getGameRecord";
|
import { getGameRecord } from "./getGameRecord";
|
||||||
import { getLTokenBySToken } from "./getLToken";
|
import { getLTokenBySToken } from "./getLToken";
|
||||||
import { getGameRoleListByLToken } from "./getRoleList";
|
import { getGameRoleListByLToken } from "./getRoleList";
|
||||||
|
import { getStokenByGameToken } from "./getStoken";
|
||||||
import getSyncAvatarDetail from "./getSyncAvatarDetail";
|
import getSyncAvatarDetail from "./getSyncAvatarDetail";
|
||||||
import getSyncAvatarListAll from "./getSyncAvatarListAll";
|
import getSyncAvatarListAll from "./getSyncAvatarListAll";
|
||||||
import { getTokensByLoginTicket } from "./getTokens";
|
import { getTokensByLoginTicket } from "./getTokens";
|
||||||
import { getUserInfoByCookie } from "./getUserInfo";
|
import { getUserInfoByCookie } from "./getUserInfo";
|
||||||
|
import { getVerification, submitVerification } from "./operVerification";
|
||||||
import { verifyLToken } from "./verifyLToken";
|
import { verifyLToken } from "./verifyLToken";
|
||||||
import { getStokenByGameToken } from "./getStoken";
|
|
||||||
|
|
||||||
const TGRequest = {
|
const TGRequest = {
|
||||||
Anno: {
|
Anno: {
|
||||||
@@ -56,6 +57,10 @@ const TGRequest = {
|
|||||||
getSyncAvatarListAll,
|
getSyncAvatarListAll,
|
||||||
getSyncAvatarDetail,
|
getSyncAvatarDetail,
|
||||||
},
|
},
|
||||||
|
verification: {
|
||||||
|
get: getVerification,
|
||||||
|
verify: submitVerification,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
84
src/web/request/operVerification.ts
Normal file
84
src/web/request/operVerification.ts
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* @file src web request operVerification.ts
|
||||||
|
* @description 验证码操作请求函数
|
||||||
|
* @since Beta v0.3.3
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TGUtils from "../utils/TGUtils";
|
||||||
|
import { http } from "@tauri-apps/api";
|
||||||
|
import showSnackbar from "../../components/func/snackbar";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 发起验证请求
|
||||||
|
* @param {string} Ltoken ltoken
|
||||||
|
* @param {string} Ltuid ltuid
|
||||||
|
* @return {Promise<TGApp.Plugins.Geetest.getData|TGApp.BBS.Response.Base>} 验证码参数
|
||||||
|
*/
|
||||||
|
export async function getVerification(
|
||||||
|
Ltoken: string,
|
||||||
|
Ltuid: string,
|
||||||
|
): Promise<TGApp.BBS.Geetest.getData | TGApp.BBS.Response.Base> {
|
||||||
|
const url = "https://api-takumi-record.mihoyo.com/game_record/app/card/wapi/createVerification";
|
||||||
|
const cookie = {
|
||||||
|
ltoken: Ltoken,
|
||||||
|
ltuid: Ltuid,
|
||||||
|
};
|
||||||
|
const params = { is_high: "true" };
|
||||||
|
const header = TGUtils.User.getHeader(cookie, "GET", params, "common");
|
||||||
|
return await http
|
||||||
|
.fetch<TGApp.BBS.Geetest.getResponse>(url, {
|
||||||
|
method: "GET",
|
||||||
|
headers: header,
|
||||||
|
query: params,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.data.retcode !== 0) return res.data;
|
||||||
|
return res.data.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 将验证完的参数提交给米游社
|
||||||
|
* @since Beta v0.3.3
|
||||||
|
* @todo 待测试
|
||||||
|
* @param {Record<string, string>} cookie cookie
|
||||||
|
* @param {TGApp.BBS.Geetest.GeetestValidate} validate 验证码参数
|
||||||
|
* @return {Promise<TGApp.BBS.Response.Base|unknown>} 提交结果
|
||||||
|
*/
|
||||||
|
export async function submitVerification(
|
||||||
|
cookie: Record<string, string>,
|
||||||
|
validate: TGApp.BBS.Geetest.GeetestValidate,
|
||||||
|
): Promise<TGApp.BBS.Response.Base | unknown> {
|
||||||
|
const url = "https://api-takumi-record.mihoyo.com/game_record/app/card/wapi/verifyVerification";
|
||||||
|
const data = {
|
||||||
|
geetest_challenge: validate.geetest_challenge,
|
||||||
|
geetest_validate: validate.geetest_validate,
|
||||||
|
geetest_seccode: validate.geetest_seccode,
|
||||||
|
};
|
||||||
|
console.log(data);
|
||||||
|
const header = TGUtils.User.getHeader(cookie, "POST", data, "lk2", true);
|
||||||
|
const reqHeader = {
|
||||||
|
...header,
|
||||||
|
"x-rpc-challenge_game": "2",
|
||||||
|
"x-rpc-challenge_trace": validate.geetest_challenge,
|
||||||
|
"x-rpc-validate": validate.geetest_validate,
|
||||||
|
"x-rpc-seccode": validate.geetest_seccode,
|
||||||
|
};
|
||||||
|
console.log(reqHeader);
|
||||||
|
return await http
|
||||||
|
.fetch<TGApp.BBS.Response.Base>(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: reqHeader,
|
||||||
|
body: http.Body.json(data),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.data.retcode !== 0) {
|
||||||
|
showSnackbar({
|
||||||
|
text: `[${res.data.retcode}] ${res.data.message}`,
|
||||||
|
color: "error",
|
||||||
|
});
|
||||||
|
console.error(res.data);
|
||||||
|
}
|
||||||
|
return res.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user