feat(huya): device_mint 铸币机编排器 + 登录链验收矩阵(铸币hdid→APP_SIGN/金样本→NEED_RISK)

- tools/device_mint.py: --mint-only/--login/--control/--matrix 全编排
- huya_launch_mint.mint_sguid(): 上线铸币函数
- docs §11.9: 接受度矩阵 + 边界精确化 (sGuid可铸/登录签名独立硬锚)
This commit is contained in:
yml2213
2026-08-28 22:31:30 +08:00
parent ccfa742e3b
commit 9ff572191c
3 changed files with 184 additions and 0 deletions
+123
View File
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
"""虎牙铸币机 —— 全管线编排: mid(铸) → doLaunch 收 sGuid → 零设备注册链 → WUP 登录验证.
铸币闭环 (docs/HUYA_HDID_ALGORITHM_GEN.md §11.8):
sGuid = f(mid) —— 服务端按 mid(LiveUserbase→tUAEx→t5=sMId, 16hex) 确定性签发。
mid 可任意铸造 → doLaunch 收 32hex sGuid → 登录帧 t1.t0(hdid) 用该 sGuid。
用法:
python tools/device_mint.py --mint-only [mid] # 只铸币: mid → sGuid
python tools/device_mint.py --login <acct> <pwd> [--mid X] # 铸币 → 注册链 → 登录
python tools/device_mint.py --control <acct> <pwd> # 金样本 hdid 登录 (对照基线)
python tools/device_mint.py --matrix <acct> <pwd> # 双雨矩阵: 3 个 mid ×2 复跑 + 登录
输出: cred hex / NEED_RISK / REJECTED 对照; 事件实时打印。
"""
from __future__ import annotations
import hashlib
import sys
from pathlib import Path
HERE = Path(__file__).resolve().parent
if str(HERE) not in sys.path:
sys.path.insert(0, str(HERE))
from huya_launch_mint import DEFAULT_PROFILE, mint_sguid # noqa: E402
try:
from huya_device_register import gen_fresh_identity, login_with_registered # noqa: E402
HAVE_REG = True
except Exception: # pragma: no cover
HAVE_REG = False
GOLDEN_HDID = "ed0db8334cadd236c00cadf7e11ab5a5" # 金样本 hdid (对照基线)
URL = "https://wup.huya.com"
def mint_couple(mid: str, times: int = 2) -> list[str | None]:
"""同一 mid 铸币多次, 验证确定性。"""
out = []
for _ in range(times):
out.append(mint_sguid(DEFAULT_PROFILE, mid=mid, url=URL))
return out
def full_mint_login(account: str, password: str, mid: str) -> str:
"""铸币→注册链→登录 (铸币 hdid), 返回 cred hex / NEED_RISK / REJECTED。"""
sguid = mint_sguid(DEFAULT_PROFILE, mid=mid, url=URL)
print(f"[mint] mid={mid} -> sGuid={sguid}")
if not sguid:
return "REJECTED:no-sguid"
if not HAVE_REG:
return "REJECTED:no-reg-chain"
t1, t2, t5 = gen_fresh_identity()
print(f"[reg] t1(appkey回声)={t1}")
print(f"[reg] t2(action)={t2[:16]}... len={len(t2)}")
print(f"[reg] t5(device_id)={t5}")
out = login_with_registered(t2, t5, account, password, golden_hdid=sguid)
print(f"[login] 铸币hdid={sguid} -> {_brief(out)}")
return out
def full_control_login(account: str, password: str) -> str:
"""对照: 金样本 hdid 登录 (注册链仍走零设备)。"""
if not HAVE_REG:
return "REJECTED:no-reg-chain"
t1, t2, t5 = gen_fresh_identity()
print(f"[reg] t1={t1} t2={t2[:16]}... t5={t5}")
out = login_with_registered(t2, t5, account, password, golden_hdid=GOLDEN_HDID)
print(f"[login] 金样本hdid={GOLDEN_HDID} -> {_brief(out)}")
return out
def _brief(out: str) -> str:
if out.startswith(("0a", "0b")):
return "cred " + out[:16] + "..."
return out
def main() -> int:
argv = sys.argv[1:]
if len(argv) >= 2 and argv[0] == "--mint-only":
mid = argv[1] if len(argv) > 1 else DEFAULT_PROFILE["mid"]
r = mint_couple(mid, times=3)
print(f"mid={mid} 铸币×3: {r}")
ok = len({x for x in r}) == 1 and r[0] is not None
print("确定性:", "✅ 三次同值" if ok else "❌ 不一致/失败")
return 0 if ok else 2
if len(argv) >= 3 and argv[0] in ("--login", "--control", "--matrix"):
acct, pwd = argv[1], argv[2]
if "--mid" in argv:
mid = argv[argv.index("--mid") + 1]
else:
mid = DEFAULT_PROFILE["mid"]
if argv[0] == "--login":
out = full_mint_login(acct, pwd, mid)
print("最终:", _brief(out))
return 0 if out.startswith(("0a", "0b")) else 1
if argv[0] == "--control":
out = full_control_login(acct, pwd)
print("最终:", _brief(out))
return 0 if out.startswith(("0a", "0b")) else 1
# --matrix: 3 mid ×2 复跑 (确定性) + 铸币登录 vs 金样本登录
print("=== 铸币确定性矩阵 (mid → sGuid ×2) ===")
mids = [DEFAULT_PROFILE["mid"], "9c41d0a7b3e5f281", "31415f26a7c8b9d0"]
for m in mids:
r = mint_couple(m, times=2)
print(f"mid={m}: {r} {'' if len({x for x in r}) == 1 and r[0] else ''}")
print("\n=== 铸币 hdid 登录 (零设备注册链) ===")
out1 = full_mint_login(acct, pwd, mid)
print("\n=== 对照: 金样本 hdid 登录 ===")
out2 = full_control_login(acct, pwd)
print(f"\n铸币 hdid -> {_brief(out1)}")
print(f"金样本 -> {_brief(out2)}")
return 0 if out1.startswith(("0a", "0b")) else 1
print(__doc__)
return 2
if __name__ == "__main__":
raise SystemExit(main())