type: 收敛测试 schemas 与协议层类型
This commit is contained in:
+44
-19
@@ -18,6 +18,7 @@
|
||||
- 滑块 UA / session / traceId 用金样本常量 -> 与随机机型画像不自洽;
|
||||
- qr_auth(扫码)/dx_auth(短信) 无自动闭环 -> 碰上直接失败(QR_AUTH_REQUIRED)。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
@@ -176,13 +177,13 @@ def parse_cred(resp: bytes) -> bytes | None:
|
||||
e = resp.find(b"_wup_header")
|
||||
if s < 0 or e < 0:
|
||||
return None
|
||||
d = resp[s:e - 6]
|
||||
d = resp[s : e - 6]
|
||||
m = re.search(rb"\x3d\x00([\x00-\x03])(.)", d)
|
||||
if not m:
|
||||
return None
|
||||
ln = m.group(2)[0]
|
||||
st = m.start() + 4
|
||||
cred = d[st:st + ln]
|
||||
cred = d[st : st + ln]
|
||||
if len(cred) == 114 and cred[:1] == b"\x0a":
|
||||
return cred
|
||||
return None
|
||||
@@ -209,7 +210,10 @@ def solve_safe_auth(risk_url: str, proxies=None, max_retry: int = 3) -> dict:
|
||||
HuyaVerificationSolver,
|
||||
)
|
||||
|
||||
q = {k: v[0] for k, v in parse_qs(urlparse(risk_url).query, keep_blank_values=True).items()}
|
||||
q = {
|
||||
k: v[0]
|
||||
for k, v in parse_qs(urlparse(risk_url).query, keep_blank_values=True).items()
|
||||
}
|
||||
app_id = str(q.get("appId") or "5002")
|
||||
last_err: Exception | None = None
|
||||
for attempt in range(max_retry):
|
||||
@@ -287,7 +291,11 @@ def login_cred_with_flow(
|
||||
return cred, uid
|
||||
risk_url = parse_risk_url(resp)
|
||||
if risk_url:
|
||||
kind = "pt_auth(滑块)" if "pt_auth" in risk_url else ("qr_auth(扫码)" if "qr_auth" in risk_url else "未知")
|
||||
kind = (
|
||||
"pt_auth(滑块)"
|
||||
if "pt_auth" in risk_url
|
||||
else ("qr_auth(扫码)" if "qr_auth" in risk_url else "未知")
|
||||
)
|
||||
logger.info(f"[huya-app] 第 {rnd + 1} 轮触发安全验证: {kind}")
|
||||
if "qr_auth" in risk_url:
|
||||
raise HuyaAppQrAuthRequiredError(
|
||||
@@ -317,12 +325,14 @@ class QrRole:
|
||||
self.context = f"{prefix}-{ctx_hex}-{tail}"
|
||||
self.page_id = random.randint(40_000_000, 41_000_000)
|
||||
self.req_counter = random.randint(40_000_000, 41_000_000)
|
||||
self.s.headers.update({
|
||||
"User-Agent": UA_PC if pc else APP_UA_MOBILE,
|
||||
"Origin": UDB_BASE,
|
||||
"content-type": "application/json;charset=UTF-8",
|
||||
"Accept": "*/*",
|
||||
})
|
||||
self.s.headers.update(
|
||||
{
|
||||
"User-Agent": UA_PC if pc else APP_UA_MOBILE,
|
||||
"Origin": UDB_BASE,
|
||||
"content-type": "application/json;charset=UTF-8",
|
||||
"Accept": "*/*",
|
||||
}
|
||||
)
|
||||
|
||||
def _headers(self, uri: str) -> dict:
|
||||
mid = "2.6" if self.pc else "2.5"
|
||||
@@ -334,7 +344,9 @@ class QrRole:
|
||||
"Referer": f"{UDB_BASE}/web/middle/{mid}/{self.page_id}/https/{self.context.split('-')[1]}",
|
||||
}
|
||||
|
||||
def call(self, path: str, uri: str, data: dict, cookies: dict | None = None) -> dict:
|
||||
def call(
|
||||
self, path: str, uri: str, data: dict, cookies: dict | None = None
|
||||
) -> dict:
|
||||
envelope = {
|
||||
"uri": uri,
|
||||
"version": "2.6" if self.pc else "2.5",
|
||||
@@ -389,13 +401,16 @@ 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
|
||||
self.device_info = device_info or get_profile(self.username, force_new=force_new_device)
|
||||
self.device_info = device_info or get_profile(
|
||||
self.username, force_new=force_new_device
|
||||
)
|
||||
|
||||
def login(self) -> HuyaLoginResult:
|
||||
"""执行完整 App 登录获取 Cookie 流程 (成功/失败均记录登录时间 → 设备绑定页)。"""
|
||||
result = self._login_impl()
|
||||
try:
|
||||
from .device_profile import record_login
|
||||
|
||||
record_login(self.username, result.success, result.message)
|
||||
except Exception: # 元数据记录失败不影响登录结果
|
||||
pass
|
||||
@@ -404,7 +419,9 @@ class HuyaAppPasswordLogin:
|
||||
def _login_impl(self) -> HuyaLoginResult:
|
||||
"""登录主体 (原 login)。"""
|
||||
acct = self.username
|
||||
logger.info(f"[huya-app] 开始登录账号 {acct} (机型: {self.device_info.get('model')})...")
|
||||
logger.info(
|
||||
f"[huya-app] 开始登录账号 {acct} (机型: {self.device_info.get('model')})..."
|
||||
)
|
||||
|
||||
# 1) 获取新鲜 cred 与 真实 uid (自动过 safe_auth 滑块)
|
||||
try:
|
||||
@@ -442,7 +459,9 @@ class HuyaAppPasswordLogin:
|
||||
|
||||
# 3) 信封补丁
|
||||
raw = bytearray(env.raw)
|
||||
raw[env.cert_off:env.cert_off + env.cert_len] = cert.encode("ascii")
|
||||
if env.cert_off is None or env.uid_off is None:
|
||||
raise ValueError("信封缺少证书或 uid 偏移")
|
||||
raw[env.cert_off : env.cert_off + env.cert_len] = cert.encode("ascii")
|
||||
if env.uid != uid:
|
||||
struct.pack_into(">Q", raw, env.uid_off, uid)
|
||||
wup = base64.b64encode(bytes(raw)).decode("ascii")
|
||||
@@ -457,9 +476,11 @@ class HuyaAppPasswordLogin:
|
||||
try:
|
||||
# 一号一设备: sdid 状态按账号隔离 (默认全局目录会让所有账号共享
|
||||
# 同一份 hydevice 设备状态, 服务端可跨账号关联 — 见 R40 缺口修复)
|
||||
sdid_obj = get_huya_sdid(allow_fallback=True,
|
||||
state_dir=account_state_dir(self.username),
|
||||
device_hint=self.device_info)
|
||||
sdid_obj = get_huya_sdid(
|
||||
allow_fallback=True,
|
||||
state_dir=account_state_dir(self.username),
|
||||
device_hint=self.device_info,
|
||||
)
|
||||
sdid = sdid_obj.sdid if sdid_obj else ""
|
||||
pc = QrRole(pc=True, sdid=sdid, proxies=self.proxies)
|
||||
ph = QrRole(pc=False, sdid=sdid, proxies=self.proxies)
|
||||
@@ -502,7 +523,9 @@ class HuyaAppPasswordLogin:
|
||||
},
|
||||
)
|
||||
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')}")
|
||||
logger.warning(
|
||||
f"[huya-app] bind 返回码: {r2.get('returnCode')} msg: {r2.get('message')}"
|
||||
)
|
||||
|
||||
# 4.3 轮询 tryQrLogin
|
||||
biztoken = None
|
||||
@@ -552,7 +575,9 @@ class HuyaAppPasswordLogin:
|
||||
code="COOKIE_INCOMPLETE",
|
||||
)
|
||||
|
||||
logger.info(f"[huya-app] 账号 {acct} 登录成功,获取完整 Cookie ({len(cookie_str)}B)")
|
||||
logger.info(
|
||||
f"[huya-app] 账号 {acct} 登录成功,获取完整 Cookie ({len(cookie_str)}B)"
|
||||
)
|
||||
return HuyaLoginResult(
|
||||
success=True,
|
||||
cookie=cookie_str,
|
||||
|
||||
Reference in New Issue
Block a user