#!/usr/bin/env python3 """一键全自动(含新账号safe_auth滑块): 账号密码 -> 页面cookie(biztoken)。 与 full_auto_test.py 的区别: 可信账号直出cred之外, 新/异地账号触发 safe_auth 时自动解 udbrtt 滑块并重发登录, 全程零人工。 用法: .venv/bin/python tools/full_auto_safe.py <账号如hy_xxx或300023887> <密码> 前提: evidence/cert_keycap.json 内有较新鲜的 wupData 信封 (过期则先在设备上跑 scripts/hook_cert_keycap.py 刷新)。 """ import base64 import json import re import subprocess import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT)) sys.path.insert(0, str(ROOT / "tools")) from app_login_flow import QrAuthRequiredError, login_cred # noqa: E402 from cert_forge import build_p1, decrypt_cert, forge_cert, parse_p1 # noqa: E402 from envelope_forge import Envelope # noqa: E402 def forge(cred: bytes) -> str: """复用信封原证书的nonce/指纹/key_idx仅换cred(纯随机nonce必40020).""" env = Envelope.load() orig = base64.b64decode(env.cert_b64) f = parse_p1(decrypt_cert(orig)) P1 = build_p1(f["app_id"], f["fingerprint"], cred, rnd=f["rnd"]) return forge_cert(P1, key_idx=orig[1]).hex() def bind_for_cookie(cred_json_path: Path) -> bool: """复用扫码绑定四步流(QrRole), 返回是否拿到biztoken。""" probe = ROOT / "scripts/probe_forge_cert_bind.py" src = probe.read_text() src = re.sub(r'open\("evidence/hycred_[a-z_]+\.json"\)', f'open("{cred_json_path.as_posix()}")', src) tmp = ROOT / "scripts/_probe_auto.py" tmp.write_text(src) r = subprocess.run([sys.executable, str(tmp)], capture_output=True, text=True) print(r.stdout[-800:]) return '"ok": true' in r.stdout or "'ok': True" in r.stdout def main() -> int: acct, pwd = sys.argv[1], sys.argv[2] print("[1/3] 纯Python密码登录 (遇safe_auth自动过滑块) ...") try: cred = login_cred(acct, pwd) except QrAuthRequiredError as exc: print(f"❌ {exc}") return 2 print(f" cred OK: {len(cred)}B {cred[:8].hex()}") print("[2/3] 铸造证书 ...") cert_hex = forge(cred) out = ROOT / "evidence/auto_test_cred.json" out.write_text(json.dumps({"p1": "", "cert_hex": cert_hex, "cred_hex": cred.hex()})) print(f" 证书 OK: {len(cert_hex)//2}B") print("[3/3] 扫码绑定取cookie ...") if bind_for_cookie(out): print("\n🎉 全链路成功: 密码已换出页面cookie(biztoken)!") return 0 print("\n❌ 绑定失败——若40020多为信封过期, 请刷新wupData后重试") return 1 if __name__ == "__main__": raise SystemExit(main())