修复虎牙手机号登录并统一部署项目名

This commit is contained in:
yml2213
2026-08-31 16:11:08 +08:00
parent 09ab80e062
commit 76b14b69b7
10 changed files with 223 additions and 20 deletions
+47 -5
View File
@@ -37,7 +37,7 @@ from loguru import logger
from .cert_forge import build_p1, decrypt_cert, forge_cert, parse_p1
from .cookie_utils import normalize_huya_cookie
from .device_fingerprint import account_state_dir, get_huya_sdid
from .device_fingerprint import account_state_dir, get_huya_sdid, reset_account_state
from .device_profile import get_profile, mobile_user_agent
from .dfp_register import DfpRegistrationError, register_device
from .envelope_forge import Envelope
@@ -61,6 +61,8 @@ APP_UA_MOBILE = (
"Chrome/149.0.7827.159 Mobile Safari/537.36 huya adr/13.4.22/xiaomi/30"
)
SessionAssets = tuple[dict, str, str]
RISK_URL_RE = re.compile(rb"https://aq\.huya\.com/p/safe_auth/[^\x00-\x20\"'\\<>]+")
_URL_TAIL_KEEP = set(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=%"
@@ -123,6 +125,7 @@ def wup_password_login_raw(
safedeviceid: str | None = None,
hdid: str | None = None,
proxies: dict | None = None,
session_assets: SessionAssets | None = None,
) -> bytes:
"""发送 WUP 密码登录,返回原始响应字节。
@@ -132,7 +135,7 @@ def wup_password_login_raw(
"""
uid_str = account.removeprefix("hy_")
dev = dict(device_info) if device_info is not None else get_profile(account)
mj, ua, _old_sd = _golden_session_assets()
mj, ua, _old_sd = session_assets or _golden_session_assets()
if not safedeviceid:
try:
_t1, safedeviceid, registered_device_id = register_device(
@@ -202,6 +205,16 @@ def parse_risk_url(resp: bytes) -> str | None:
return (pt or urls)[0]
def _response_markers(resp: bytes) -> str:
"""提取 WUP 错误响应中的短 ASCII 字段,便于区分签名和凭据失败。"""
markers = []
for raw in re.findall(rb"[ -~]{4,}", resp):
value = raw.decode("ascii", "ignore")
if value not in markers and len(value) <= 160:
markers.append(value)
return ", ".join(markers[:8])
def solve_safe_auth(
risk_url: str,
proxies=None,
@@ -282,19 +295,27 @@ def login_cred_with_flow(
except DfpRegistrationError as exc:
raise HuyaAppLoginError(f"新设备注册失败: {exc}") from exc
dev["device_id"] = registered_device_id
# 风控验证绑定首次 WUP 请求的 session/traceId;所有重发必须复用它们。
session_assets = _golden_session_assets()
for rnd in range(max_rounds):
logger.debug(f"[huya-app] WUP 登录请求第 {rnd + 1} 轮...")
resp = wup_password_login_raw(
account,
password,
device_info=dev,
safedeviceid=safedeviceid,
proxies=proxies,
session_assets=session_assets,
)
cred = parse_cred(resp)
risk_url = parse_risk_url(resp) if not cred else None
logger.debug(
f"[huya-app] WUP 第 {rnd + 1} 轮响应: {len(resp)}B, "
f"cred={bool(cred)}, risk={bool(risk_url)}"
)
if cred:
uid = parse_real_uid(resp)
return cred, uid
risk_url = parse_risk_url(resp)
if risk_url:
kind = (
"pt_auth(滑块)"
@@ -309,7 +330,18 @@ def login_cred_with_flow(
solve_safe_auth(risk_url, proxies=proxies, device_info=dev)
logger.info("[huya-app] safe_auth 滑块过验成功,重发 WUP 登录...")
continue
raise HuyaAppLoginError("登录未返回凭据也无风控URL(密码错误或账号状态异常)")
markers = _response_markers(resp)
detail = f",服务端字段: {markers}" if markers else ""
logger.warning(f"[huya-app] WUP 响应未包含 cred/风控: {len(resp)}B{detail}")
if "LGN_INFO_INVALID_USER_OR_PASSWORD" in markers:
raise HuyaAppLoginError(
"虎牙账号或密码错误(服务端: LGN_INFO_INVALID_USER_OR_PASSWORD"
)
if "APP_SIGN_NOT_MATCH" in markers:
raise HuyaAppLoginError("虎牙设备签名不匹配(服务端: APP_SIGN_NOT_MATCH")
raise HuyaAppLoginError(
f"登录未返回凭据也无风控URL(响应 {len(resp)}B{detail}"
)
raise HuyaAppLoginError(f"{max_rounds} 轮内未取得登录凭据")
@@ -414,6 +446,8 @@ class HuyaAppPasswordLogin:
self.proxies = dict(proxies) if proxies else None
self.timeout = timeout or (10.0, 25.0)
self.force_new_device = force_new_device
if force_new_device:
reset_account_state(self.username)
self.device_info = device_info or get_profile(
self.username, force_new=force_new_device
)
@@ -495,6 +529,7 @@ class HuyaAppPasswordLogin:
device_hint=self.device_info,
)
sdid = sdid_obj.sdid if sdid_obj else ""
logger.info("[huya-app] cred 已获取,开始二维码绑定流程")
pc = QrRole(pc=True, sdid=sdid, proxies=self.proxies)
ph = QrRole(
pc=False,
@@ -511,6 +546,7 @@ class HuyaAppPasswordLogin:
{"behavior": beh, "type": "", "domainList": "", "page": page},
)
qrid = (resp.get("data") or {}).get("qrId")
logger.debug(f"[huya-app] getQrId 响应: qrid={bool(qrid)}")
if not qrid:
return HuyaLoginResult(
success=False,
@@ -540,6 +576,9 @@ class HuyaAppPasswordLogin:
"page": quote(cp, safe=""),
},
)
logger.debug(
f"[huya-app] bindQrLoginUser 响应: returnCode={r2.get('returnCode')}"
)
if r2.get("returnCode") not in (0, "0", None) and r2.get("returnCode") != 0:
logger.warning(
f"[huya-app] bind 返回码: {r2.get('returnCode')} msg: {r2.get('message')}"
@@ -547,7 +586,7 @@ class HuyaAppPasswordLogin:
# 4.3 轮询 tryQrLogin
biztoken = None
for _ in range(12):
for index in range(12):
rt = pc.call(
"/qrLgn/tryQrLogin",
"70003",
@@ -560,6 +599,9 @@ class HuyaAppPasswordLogin:
},
)
dt = rt.get("data") or {}
logger.debug(
f"[huya-app] tryQrLogin 第 {index + 1}/12 轮: stage={dt.get('stage')}"
)
if dt.get("stage") == 2:
biztoken = dt.get("biztoken")
break