mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-03-26 05:39:45 +08:00
@@ -96,6 +96,7 @@
|
||||
"pinia": "^3.0.4",
|
||||
"pinia-plugin-persistedstate": "^4.7.1",
|
||||
"qrcode.vue": "^3.6.0",
|
||||
"rsa-oaep-encryption": "^1.1.0",
|
||||
"sass-embedded": "^1.97.1",
|
||||
"swiper": "^12.0.3",
|
||||
"uuid": "^13.0.0",
|
||||
|
||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -86,6 +86,9 @@ importers:
|
||||
qrcode.vue:
|
||||
specifier: ^3.6.0
|
||||
version: 3.6.0(vue@3.5.26(typescript@5.9.3))
|
||||
rsa-oaep-encryption:
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0
|
||||
sass-embedded:
|
||||
specifier: ^1.97.1
|
||||
version: 1.97.1
|
||||
@@ -3576,6 +3579,9 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
rsa-oaep-encryption@1.1.0:
|
||||
resolution: {integrity: sha512-GzbbyA//t8Safvj2k4KrGjuA1iHHrvCqkjCG49aOO9tdMV+CG0nNjuUNqRUibz5QoO851u24n/wgbSMi6ZZ01w==}
|
||||
|
||||
run-applescript@7.1.0:
|
||||
resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -7864,6 +7870,8 @@ snapshots:
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.53
|
||||
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.53
|
||||
|
||||
rsa-oaep-encryption@1.1.0: {}
|
||||
|
||||
run-applescript@7.1.0: {}
|
||||
|
||||
run-parallel@1.2.0:
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
"http:allow-fetch",
|
||||
"log:default",
|
||||
"log:allow-log",
|
||||
"machine-uid:default",
|
||||
"machine-uid:allow-get-machine-uid",
|
||||
"notification:default",
|
||||
"opener:default",
|
||||
"process:default",
|
||||
|
||||
@@ -19,22 +19,18 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import showDialog from "@comp/func/dialog.js";
|
||||
import showSnackbar from "@comp/func/snackbar.js";
|
||||
import {
|
||||
isPermissionGranted,
|
||||
requestPermission,
|
||||
sendNotification,
|
||||
} from "@tauri-apps/plugin-notification";
|
||||
import hutao from "@Hutao/index.js";
|
||||
|
||||
async function test() {
|
||||
const check = await isPermissionGranted();
|
||||
console.log(check);
|
||||
if (!check) {
|
||||
showSnackbar.warn("没有通知权限");
|
||||
const permission = await requestPermission();
|
||||
console.log(permission);
|
||||
const inputN = await showDialog.input("UserName");
|
||||
const inputP = await showDialog.input("Pwd");
|
||||
if (!inputN || !inputP) return;
|
||||
const resp = await hutao.Account.login(inputN, inputP);
|
||||
if ("retcode" in resp) {
|
||||
showSnackbar.warn(`${resp.retcode}-${resp.message}`);
|
||||
}
|
||||
sendNotification({ title: "New Message", body: "You have a new message" });
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Hutao 插件入口
|
||||
* @since Beta v0.6.3
|
||||
* @since Beta v0.9.1
|
||||
*/
|
||||
|
||||
import {
|
||||
@@ -12,10 +12,13 @@ import {
|
||||
getTeamCollect,
|
||||
uploadAbyssData,
|
||||
} from "./request/abyssReq.js";
|
||||
import { loginPassport } from "./request/accountReq.js";
|
||||
import { getCombatStatistic, uploadCombatData } from "./request/combatReq.js";
|
||||
import { transAbyssAvatars, transAbyssLocal } from "./utils/abyssUtil.js";
|
||||
import { transCombatLocal } from "./utils/combatUtil.js";
|
||||
|
||||
const _ = "Not Implemented";
|
||||
|
||||
const Hutao = {
|
||||
Abyss: {
|
||||
avatar: {
|
||||
@@ -37,6 +40,27 @@ const Hutao = {
|
||||
data: getCombatStatistic,
|
||||
trans: transCombatLocal,
|
||||
},
|
||||
Account: {
|
||||
register: _,
|
||||
login: loginPassport,
|
||||
verify: _,
|
||||
cancel: _,
|
||||
reset: {
|
||||
username: _,
|
||||
password: _,
|
||||
},
|
||||
token: {
|
||||
refresh: _,
|
||||
revoke: _,
|
||||
revokeAll: _,
|
||||
},
|
||||
info: _,
|
||||
},
|
||||
Gacha: {
|
||||
log: _,
|
||||
upload: _,
|
||||
delete: _,
|
||||
},
|
||||
};
|
||||
|
||||
export default Hutao;
|
||||
|
||||
66
src/plugins/Hutao/request/accountReq.ts
Normal file
66
src/plugins/Hutao/request/accountReq.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 账号相关请求
|
||||
* @since Beta v0.9.1
|
||||
*/
|
||||
|
||||
import TGHttp from "@utils/TGHttp.js";
|
||||
import { importPublicKey, sha1 } from "rsa-oaep-encryption";
|
||||
|
||||
import { getReqHeader } from "../utils/authUtils.js";
|
||||
|
||||
/** 加密公钥 */
|
||||
const HUTAO_PUB_KEY: Readonly<string> = `
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5W2SEyZSlP2zBI1Sn8Gd
|
||||
TwbZoXlUGNKyoVrY8SVYu9GMefdGZCrUQNkCG/Np8pWPmSSEFGd5oeug/oIMtCZQ
|
||||
NOn0drlR+pul/XZ1KQhKmj/arWjN1XNok2qXF7uxhqD0JyNT/Fxy6QvzqIpBsM9S
|
||||
7ajm8/BOGlPG1SInDPaqTdTRTT30AuN+IhWEEFwT3Ctv1SmDupHs2Oan5qM7Y3uw
|
||||
b6K1rbnk5YokiV2FzHajGUymmSKXqtG1USZzwPqImpYb4Z0M/StPFWdsKqexBqMM
|
||||
mkXckI5O98GdlszEmQ0Ejv5Fx9fR2rXRwM76S4iZTfabYpiMbb4bM42mHMauupj6
|
||||
9QIDAQAB
|
||||
-----END PUBLIC KEY-----`;
|
||||
const encrypt = importPublicKey(HUTAO_PUB_KEY);
|
||||
|
||||
const PassportUrl = "https://homa.gentle.house/Passport/v2/";
|
||||
|
||||
/**
|
||||
* rsa 加密
|
||||
* @since Beta v0.9.1
|
||||
* @param data - 待加密数据
|
||||
* @returns 加密后数据
|
||||
*/
|
||||
function rsaEncrypt(data: string): string {
|
||||
const res = encrypt.encrypt(data, sha1.create());
|
||||
const bytes = new Uint8Array(res);
|
||||
let binary = "";
|
||||
for (let i = 0; i < bytes.byteLength; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return btoa(binary);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录
|
||||
* @since Beta v0.9.1
|
||||
* @param username - 用户名(邮箱)
|
||||
* @param password - 密码
|
||||
* @returns
|
||||
*/
|
||||
export async function loginPassport(
|
||||
username: string,
|
||||
password: string,
|
||||
): Promise<TGApp.Plugins.Hutao.Account.LoginRes | TGApp.Plugins.Hutao.Base.Resp> {
|
||||
const url = `${PassportUrl}Login`;
|
||||
const data = {
|
||||
UserName: rsaEncrypt(username),
|
||||
Password: rsaEncrypt(password),
|
||||
};
|
||||
const header = await getReqHeader();
|
||||
const resp = await TGHttp<TGApp.Plugins.Hutao.Account.LoginResp>(url, {
|
||||
method: "POST",
|
||||
headers: header,
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (resp.retcode !== 0) return <TGApp.Plugins.Hutao.Base.Resp>resp;
|
||||
return resp.data;
|
||||
}
|
||||
58
src/plugins/Hutao/types/Account.d.ts
vendored
Normal file
58
src/plugins/Hutao/types/Account.d.ts
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 账号请求相关类型
|
||||
* @since Beta v0.9.1
|
||||
*/
|
||||
|
||||
declare namespace TGApp.Plugins.Hutao.Account {
|
||||
/**
|
||||
* Passport 请求参数
|
||||
* @since Beta v0.9.1
|
||||
*/
|
||||
type PassportReqParams = {
|
||||
/** 设备ID */
|
||||
DeviceId: string;
|
||||
/** 邮箱 */
|
||||
UserName: string | null;
|
||||
/**
|
||||
* 新邮箱
|
||||
* @remarks 用于账号迁移
|
||||
*/
|
||||
NewUserName: string | null;
|
||||
/** 密码 */
|
||||
Password: string | null;
|
||||
/** 邮箱验证码 */
|
||||
VerifyCode: string | null;
|
||||
/**
|
||||
* 新邮箱验证码
|
||||
* @remarks 用于账号迁移
|
||||
*/
|
||||
NewVerifyCode: string | null;
|
||||
/** 重置密码Flag */
|
||||
IsResetPassword: boolean;
|
||||
/** 校验邮箱Flag */
|
||||
IsResetUserName: boolean;
|
||||
/** 校验新邮箱Flag */
|
||||
IsResetNewUserName: boolean;
|
||||
/** 注销账号Flag */
|
||||
IsCancelRegistration: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* 登录请求响应
|
||||
* @since Beta v0.9.1
|
||||
*/
|
||||
type LoginResp = TGApp.Plugins.Hutao.Base.Resp<LoginRes>;
|
||||
|
||||
/**
|
||||
* 登录请求返回
|
||||
* @since Beta v0.9.1
|
||||
*/
|
||||
type LoginRes = {
|
||||
/** token */
|
||||
AccessToken: string;
|
||||
/** expire */
|
||||
ExpiresIn: number;
|
||||
/** refresh */
|
||||
RefreshToken: string;
|
||||
};
|
||||
}
|
||||
27
src/plugins/Hutao/utils/authUtils.ts
Normal file
27
src/plugins/Hutao/utils/authUtils.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 账号认证相关方法
|
||||
* @since Beta v0.9.1
|
||||
*/
|
||||
import { commands } from "@skipperndt/plugin-machine-uid";
|
||||
import { getVersion } from "@tauri-apps/api/app";
|
||||
|
||||
let DEVICE_ID: string | null = null;
|
||||
|
||||
/**
|
||||
* 获取请求头
|
||||
* @since Beta v0.9.1
|
||||
*/
|
||||
export async function getReqHeader(tk?: string): Promise<Record<string, string>> {
|
||||
const version = await getVersion();
|
||||
if (DEVICE_ID === null) {
|
||||
const deviceRes = await commands.getMachineUid();
|
||||
if (deviceRes.status === "ok") DEVICE_ID = deviceRes.data.id;
|
||||
}
|
||||
const device = DEVICE_ID ?? "";
|
||||
return {
|
||||
"Content-Type": "application/json",
|
||||
"x-hutao-device-id": device,
|
||||
Authorization: tk ? `Bearer ${tk}` : "",
|
||||
"User-Agent": `TeyvatGuide/${version}`,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user