From 9f3e3a74cea66fdd564972d3080b4f008724c789 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Tue, 1 Sep 2026 20:25:31 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=B4=BB=E5=8A=A8WSS=20AUTH?= =?UTF-8?q?=E5=B8=A7=E5=AF=B9=E9=BD=909.1=E6=8A=93=E5=8C=85=E5=AD=97?= =?UTF-8?q?=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/huya/wss_client.py | 20 ++++++++++++++++++-- tests/test_huya_elite_protocol.py | 22 ++++++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/core/huya/wss_client.py b/core/huya/wss_client.py index 0f8e0cd..88673be 100644 --- a/core/huya/wss_client.py +++ b/core/huya/wss_client.py @@ -568,12 +568,28 @@ class HuyaWssClient: return body async def send_auth(self, uid: int, cookie: str, sequence: int = SEQ_WSLAUNCH): - """cmd 0x0a AUTH — 发送 TAF 认证结构(与 9.1 活动帧一致)。""" + """cmd 0x0a AUTH — 对齐 9.1 抓包(828 活动帧)。 + + 9.1 活动 AUTH 结构(逐字节核验): + tag3 ZERO ← 首字段(活动通道) + tag0 INT64 = uid + tag1 STRING1 = UA + tag2 STRING4 = cookie(含 huya_ua= 前缀) + tag3 STRING1 = guid(32hex,9.1 中为页面 Cookie 的 guid) + tag4 INT8 = 1 + tag5 STRING1 = "HUYA&ZH&2052" + tag6 STRING1 = "" + += TAIL_BYTES(tag2 ZERO/tag3 ""/tag4 ZERO/tag5 ZERO/tag6 "") + """ os = TafOutputStream() + if self._activity_mode: + os.write_head(3, TafType.ZERO) os.write_int64(0, int(uid or 0)) os.write_string(1, WSS_COOKIE_UA) os.write_string(2, HuyaWssClient._normalize_biz_cookie(cookie)) - os.write_int32(3, 0) + guid_match = re.search(r"(?:^|;\s*)guid=([^;]+)", cookie or "") + guid = (guid_match.group(1).strip() if guid_match else "") or self._launch_guid + os.write_string(3, guid or "") os.write_int8(4, 1) os.write_string(5, "HUYA&ZH&2052") os.write_string(6, "") diff --git a/tests/test_huya_elite_protocol.py b/tests/test_huya_elite_protocol.py index bda58c0..71a10e6 100644 --- a/tests/test_huya_elite_protocol.py +++ b/tests/test_huya_elite_protocol.py @@ -106,10 +106,21 @@ def test_wss_requires_web_device_cookie_fields(): def test_activity_auth_frame_matches_latest_capture_layout(): + """对齐 9.1 活动 AUTH(828 连接)逐字段结构。 + + 9.1: tag3 ZERO 首字段 -> tag0 uid -> tag1 UA -> tag2 cookie(STRING4) + -> tag3 STRING1 guid(32hex) -> tag4 INT8=1 -> tag5 "HUYA&ZH&2052" + -> tag6 "" -> TAIL_BYTES + """ async def build_frame(): client = HuyaWssClient() + client._activity_mode = True client.ws = type("FakeWs", (), {"send": AsyncMock()})() - await client.send_auth(1199664135026, "udb_cred=" + "x" * 300, sequence=0x1D000109) + await client.send_auth( + 1199664135026, + "guid=" + "0a" * 16 + "; udb_cred=" + "x" * 300, + sequence=0x1D000109, + ) return client.ws.send.call_args.args[0] message = WssMessage.decode(asyncio.run(build_frame())) @@ -118,13 +129,20 @@ def test_activity_auth_frame_matches_latest_capture_layout(): assert message.body.endswith(TAIL_BYTES) stream = TafInputStream(message.body[: -len(TAIL_BYTES)]) + # 首字段:tag3 ZERO(9.1 活动帧的占位字段) + assert stream.read_head() == (3, TafType.ZERO) assert stream.read_int64(0) == 1199664135026 assert stream.read_string(1) == "webh5&0.0.1&websocket&&diypc_52775" assert stream.read_head() == (2, TafType.STRING4) cookie_len = int.from_bytes(stream.buf.read(4), "big") assert cookie_len > 255 stream.buf.read(cookie_len) - assert stream.read_int32(3) == 0 + # tag3 = STRING1 guid(9.1 中为 Cookie 里的 32hex guid) + guid = stream.read_string(3) + assert guid == "0a" * 16 assert stream.read_int8(4) == 1 assert stream.read_string(5) == "HUYA&ZH&2052" assert stream.read_string(6) == "" + + # body 必须与 9.1 828 AUTH 同样以 TAIL_BYTES 收尾 + assert message.body[-len(TAIL_BYTES):] == TAIL_BYTES