From 1f27aada4e47c670adc60695db7444097d682050 Mon Sep 17 00:00:00 2001 From: omg-xtao <100690902+omg-xtao@users.noreply.github.com> Date: Fri, 31 May 2024 10:02:44 +0800 Subject: [PATCH] :sparkles: support hoyolab verify --- modules/apihelper/client/components/verify.py | 110 +++++++++++++----- plugins/account/cookies.py | 2 + plugins/app/webapp.py | 7 +- plugins/genshin/verify.py | 13 ++- plugins/tools/challenge.py | 11 +- 5 files changed, 104 insertions(+), 39 deletions(-) diff --git a/modules/apihelper/client/components/verify.py b/modules/apihelper/client/components/verify.py index 3e4093b..7b10d9b 100644 --- a/modules/apihelper/client/components/verify.py +++ b/modules/apihelper/client/components/verify.py @@ -4,58 +4,105 @@ import time from typing import Dict, Optional, Union from httpx import Cookies +from simnet import Region +from simnet.utils.ds import generate_dynamic_secret from ..base.hyperionrequest import HyperionRequest from ...utility.devices import devices_methods -from ...utility.helpers import get_ua, get_ds +from ...utility.helpers import get_ua __all__ = ("Verify",) class Verify: HOST = "api-takumi-record.mihoyo.com" + HOST_OVER = "sg-public-api.hoyolab.com" VERIFICATION_HOST = "api.geetest.com" CREATE_VERIFICATION_URL = "/game_record/app/card/wapi/createVerification" VERIFY_VERIFICATION_URL = "/game_record/app/card/wapi/verifyVerification" - REFERER_URL = "/game_record/app/genshin/api/dailyNote" + CREATE_VERIFICATION_URL1 = "/event/toolcomsrv/risk/createGeetest" + VERIFY_VERIFICATION_URL1 = "/event/toolcomsrv/risk/verifyGeetest" + REFERER_URL = "https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote" + REFERER_URL1 = "https://bbs-api-os.hoyolab.com/game_record/app/genshin/api/dailyNote" + APP_KEY = "hk4e_game_record" GAME = "2" AJAX_URL = "/ajax.php" - USER_AGENT = get_ua() - BBS_HEADERS = { - "Accept": "application/json, text/plain, */*", - "Accept-Encoding": "gzip, deflate", - "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7", - "User-Agent": USER_AGENT, - "X-Requested-With": "com.mihoyo.hyperion", - "Referer": "https://webstatic.mihoyo.com/", - "x-rpc-page": "3.1.3_#/ys", - } - - VERIFICATION_HEADERS = { - "Accept": "*/*", - "X-Requested-With": "com.mihoyo.hyperion", - "User-Agent": USER_AGENT, - "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7", - } - - def __init__(self, account_id: int = None, cookies: Union[Dict, Cookies] = None): + def __init__(self, account_id: int = None, cookies: Union[Dict, Cookies] = None, region: Region = Region.CHINESE): self.account_id = account_id - self.client = HyperionRequest(headers=self.BBS_HEADERS, cookies=cookies) + self.region = region + self.client = HyperionRequest(headers=self.get_bbs_headers(), cookies=cookies) + + @property + def create_url(self) -> str: + return ( + self.get_url(self.HOST, self.CREATE_VERIFICATION_URL) + if self.miyoushe + else self.get_url(self.HOST_OVER, self.CREATE_VERIFICATION_URL1) + ) + + @property + def verify_url(self) -> str: + return ( + self.get_url(self.HOST, self.VERIFY_VERIFICATION_URL) + if self.miyoushe + else self.get_url(self.HOST_OVER, self.VERIFY_VERIFICATION_URL1) + ) + + @property + def referer(self) -> str: + return self.REFERER_URL if self.miyoushe else self.REFERER_URL1 + + def get_ua(self, device: str = "Paimon Build"): + return ( + f"Mozilla/5.0 (Linux; Android 12; {device}; wv) " + "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/103.0.5060.129 Mobile Safari/537.36 " + f"{'miHoYoBBS/' if self.miyoushe else 'miHoYoBBSOversea/2.55.0'}" + ) + + @property + def miyoushe(self) -> bool: + return self.region == Region.CHINESE + + def get_bbs_headers(self) -> Dict[str, str]: + return { + "Accept": "application/json, text/plain, */*", + "Accept-Encoding": "gzip, deflate", + "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7", + "User-Agent": get_ua(), + "X-Requested-With": "com.mihoyo.hyperion" if self.miyoushe else "com.mihoyo.hoyolab", + "Referer": "https://webstatic.mihoyo.com/" if self.miyoushe else "https://act.hoyolab.com/", + "x-rpc-page": "3.1.3_#/rpg", + } def get_verification_headers(self, referer: str): - headers = self.VERIFICATION_HEADERS.copy() - headers["Referer"] = referer + headers = { + "Accept": "*/*", + "X-Requested-With": "com.mihoyo.hyperion" if self.miyoushe else "com.mihoyo.hoyolab", + "User-Agent": get_ua(), + "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7", + "Referer": referer, + } return headers async def get_headers(self, data: dict = None, params: dict = None): - headers = self.BBS_HEADERS.copy() - app_version, client_type, ds = get_ds(new_ds=True, data=data, params=params) + headers = self.get_bbs_headers() + app_version, client_type, ds = generate_dynamic_secret( + region=self.region, + new_ds=self.miyoushe, + data=data, + params=params, + ) headers["x-rpc-app_version"] = app_version headers["x-rpc-client_type"] = client_type headers["DS"] = ds - headers["x-rpc-challenge_path"] = f"https://{self.HOST}{self.REFERER_URL}" + headers["x-rpc-challenge_path"] = self.referer headers["x-rpc-challenge_game"] = self.GAME + if not self.miyoushe: + headers["origin"] = "https://act.hoyolab.com" + headers["x-rpc-platform"] = "4" + headers["x-rpc-language"] = "zh-cn" + headers["x-rpc-challenge_trace"] = "undefined" await devices_methods.update_device_headers(self.account_id, headers) return headers @@ -64,15 +111,20 @@ class Verify: return f"https://{host}{url}" async def create(self, is_high: bool = False): - url = self.get_url(self.HOST, self.CREATE_VERIFICATION_URL) + url = self.create_url params = {"is_high": "true" if is_high else "false"} + if not self.miyoushe: + params["app_key"] = self.APP_KEY + headers = await self.get_headers(params=params) response = await self.client.get(url, params=params, headers=headers) return response async def verify(self, challenge: str, validate: str): - url = self.get_url(self.HOST, self.VERIFY_VERIFICATION_URL) + url = self.verify_url data = {"geetest_challenge": challenge, "geetest_validate": validate, "geetest_seccode": f"{validate}|jordan"} + if not self.miyoushe: + data["app_key"] = self.APP_KEY headers = await self.get_headers(data=data) response = await self.client.post(url, json=data, headers=headers) diff --git a/plugins/account/cookies.py b/plugins/account/cookies.py index e2f0976..1ffa708 100644 --- a/plugins/account/cookies.py +++ b/plugins/account/cookies.py @@ -18,6 +18,7 @@ from core.services.players.services import PlayersService, PlayerInfoService from gram_core.services.devices import DevicesService from gram_core.services.devices.models import DevicesDataBase as Devices from modules.apihelper.models.genshin.cookies import CookiesModel +from modules.apihelper.utility.devices import devices_methods from utils.log import logger __all__ = ("AccountCookiesPlugin",) @@ -66,6 +67,7 @@ class AccountCookiesPlugin(Plugin.Conversation): self.players_service = players_service self.player_info_service = player_info_service self.devices_service = devices_service + devices_methods.service = devices_service # noinspection SpellCheckingInspection @staticmethod diff --git a/plugins/app/webapp.py b/plugins/app/webapp.py index a033dc8..e93371a 100644 --- a/plugins/app/webapp.py +++ b/plugins/app/webapp.py @@ -39,6 +39,7 @@ class WebApp(Plugin): @handler.message(filters=filters.StatusUpdate.WEB_APP_DATA, block=False) async def app(self, update: Update, _: CallbackContext): user = update.effective_user + user_id = user.id message = update.effective_message web_app_data = message.web_app_data if web_app_data: @@ -50,9 +51,13 @@ class WebApp(Plugin): if result.code == 0: if result.path == "verify": validate = result.data.get("geetest_validate") + try: + user_id = int(result.data.get("user_id", user_id)) + except ValueError: + pass if validate is not None: try: - status = await self.challenge_system.pass_challenge(user.id, validate=validate) + status = await self.challenge_system.pass_challenge(user_id, validate=validate) except ChallengeSystemException as exc: await message.reply_text(exc.message, reply_markup=ReplyKeyboardRemove()) return diff --git a/plugins/genshin/verify.py b/plugins/genshin/verify.py index b54cc5b..bef1f5f 100644 --- a/plugins/genshin/verify.py +++ b/plugins/genshin/verify.py @@ -19,17 +19,24 @@ class VerificationPlugins(Plugin): async def verify(self, update: Update, context: CallbackContext) -> None: user = update.effective_user message = update.effective_message - logger.info("用户 %s[%s] 发出verify命令", user.full_name, user.id) + args = self.get_args(context) + user_id = user.id + if args: + try: + user_id = int(args[0]) + except ValueError: + pass + logger.info("用户 %s[%s] 发出verify命令 user_id[%s]", user.full_name, user.id, user_id) try: uid, gt, challenge = await self.challenge_system.create_challenge( - user.id, context.args is not None and len(context.args) < 1 + user_id, context.args is not None and len(context.args) < 1 ) except ChallengeSystemException as exc: await message.reply_text(exc.message) return url = ( f"{config.pass_challenge_user_web}/webapp?" - f"gt={gt}&username={context.bot.username}&command=verify&challenge={challenge}&uid={uid}" + f"gt={gt}&username={context.bot.username}&command=verify&challenge={challenge}&uid={uid}&user_id={user_id}" ) await message.reply_text( "请尽快在10秒内完成手动验证\n或发送 /web_cancel 取消操作", diff --git a/plugins/tools/challenge.py b/plugins/tools/challenge.py index 15d51e7..edcfef3 100644 --- a/plugins/tools/challenge.py +++ b/plugins/tools/challenge.py @@ -57,8 +57,6 @@ class ChallengeSystem(Plugin): raise ChallengeSystemException("用户未找到") except CookiesNotFoundError: raise ChallengeSystemException("无需验证") - if client.region != Region.CHINESE: - raise ChallengeSystemException("非法用户") if need_verify: try: await client.get_genshin_notes() @@ -70,7 +68,7 @@ class ChallengeSystem(Plugin): await client.shutdown() else: await client.shutdown() - verify = Verify(cookies=client.cookies) + verify = Verify(client.account_id, cookies=client.cookies, region=client.region) try: data = await verify.create() challenge = data["challenge"] @@ -95,8 +93,9 @@ class ChallengeSystem(Plugin): player = await self.players_service.get_player(user_id) if player is None: raise ChallengeSystemException("用户未找到") - if player.region != RegionEnum.HYPERION: - raise ChallengeSystemException("非法用户") + region = Region.CHINESE + if player.region == RegionEnum.HOYOLAB: + region = Region.OVERSEAS cookie_model = await self.cookies_service.get(player.user_id, player.account_id, player.region) if cookie_model is None: raise ChallengeSystemException("无需验证") @@ -104,7 +103,7 @@ class ChallengeSystem(Plugin): _, challenge = await self.get_challenge(player.player_id) if challenge is None: raise ChallengeSystemException("验证失效 请求已经过期") - verify = Verify(cookies=Cookies(cookie_model.data)) + verify = Verify(player.account_id, cookies=Cookies(cookie_model.data), region=region) try: await verify.verify(challenge=challenge, validate=validate) except ResponseException as exc: