执行 Ruff 安全自动修复

This commit is contained in:
yml2213
2026-08-31 10:28:14 +08:00
parent 2a1d27f953
commit b58c6b4357
145 changed files with 940 additions and 993 deletions
+7 -7
View File
@@ -33,23 +33,23 @@ if TYPE_CHECKING:
)
__all__ = [
"HuyaHttpClient",
"HuyaWssClient",
"GetUserScoreReq",
"GetUserScoreResp",
"HuyaAppLoginError",
"HuyaAppPasswordLogin",
"HuyaAppQrAuthRequiredError",
"HuyaCredentialError",
"HuyaHttpClient",
"HuyaLoginError",
"HuyaLoginResult",
"HuyaPasswordLogin",
"HuyaAppLoginError",
"HuyaAppQrAuthRequiredError",
"HuyaAppPasswordLogin",
"HuyaSmsCodeResult",
"HuyaSmsLogin",
"HuyaVerificationError",
"HuyaVerificationSolver",
"login_huya_password",
"HuyaWssClient",
"login_huya_app_password",
"login_huya_password",
"login_huya_sms",
"send_huya_sms_code",
"solve_huya_verification",
@@ -98,8 +98,8 @@ def __getattr__(name: str):
}:
from .app_login import (
HuyaAppLoginError,
HuyaAppQrAuthRequiredError,
HuyaAppPasswordLogin,
HuyaAppQrAuthRequiredError,
login_huya_app_password,
)
+1 -2
View File
@@ -35,13 +35,12 @@ import os
import sys
import time
from .app_login import HuyaAppPasswordLogin
from .device_profile import (
HDID32, # 登录帧 t1.t0 32hex 常量 (R15 公式结果, k1 来源见 R39; device_profile.py)
_load_db,
_save_db,
get_profile, # 幂等画像: 同账号永远复用同一套 (data/huya_device_profiles.json)
)
from .app_login import HuyaAppPasswordLogin
# ---------------------------------------------------------------------------
+2 -2
View File
@@ -130,7 +130,7 @@ def wup_password_login_raw(
固定 action/device_id。风控重试调用方应显式复用同一注册结果。
注册链失败抛 ``HuyaAppLoginError``,绝不静默回退旧固定值。
"""
uid_str = account[3:] if account.startswith("hy_") else account
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()
if not safedeviceid:
@@ -304,7 +304,7 @@ def login_cred_with_flow(
logger.info(f"[huya-app] 第 {rnd + 1} 轮触发安全验证: {kind}")
if "qr_auth" in risk_url:
raise HuyaAppQrAuthRequiredError(
f"该账号 App 渠道要求扫码验证(qr_auth),请先在手机虎牙 App 上正常登录一次建立设备信任。"
"该账号 App 渠道要求扫码验证(qr_auth),请先在手机虎牙 App 上正常登录一次建立设备信任。"
)
solve_safe_auth(risk_url, proxies=proxies, device_info=dev)
logger.info("[huya-app] safe_auth 滑块过验成功,重发 WUP 登录...")
-1
View File
@@ -5,7 +5,6 @@
from __future__ import annotations
import base64
import os
import struct
-1
View File
@@ -30,7 +30,6 @@ from .login import (
generate_request_id,
)
CHANGE_PASSWORD_VERSION = "2.5"
CHANGE_PASSWORD_CHECK_URI = "60011"
CHANGE_PASSWORD_SEND_SMS_URI = "60003"
-1
View File
@@ -4,7 +4,6 @@ from __future__ import annotations
from collections.abc import Iterable, Mapping
import requests
from requests.cookies import RequestsCookieJar
+5 -5
View File
@@ -116,7 +116,7 @@ class Envelope:
self._parse()
@classmethod
def load(cls, path: str | Path | None = None) -> "Envelope":
def load(cls, path: str | Path | None = None) -> Envelope:
"""加载信封模板,支持从文件加载或使用内嵌金样本。"""
if path:
p = Path(path)
@@ -136,7 +136,7 @@ class Envelope:
return cls(base64.b64decode(DEFAULT_QURL_B64))
@classmethod
def _load_from_path(cls, p: Path) -> "Envelope":
def _load_from_path(cls, p: Path) -> Envelope:
if p.suffix == ".json":
j = json.loads(p.read_text("utf-8"))
q = next(
@@ -236,7 +236,7 @@ class Envelope:
assert self.uid_off is not None
return struct.unpack_from(">Q", self.raw, self.uid_off)[0]
def patch_uid(self, uid: int) -> "Envelope":
def patch_uid(self, uid: int) -> Envelope:
assert self.uid_off is not None
struct.pack_into(">Q", self.raw, self.uid_off, uid)
return self
@@ -246,7 +246,7 @@ class Envelope:
assert self.cert_off is not None
return bytes(self.raw[self.cert_off : self.cert_off + self.cert_len])
def patch_cert(self, cert: bytes) -> "Envelope":
def patch_cert(self, cert: bytes) -> Envelope:
assert self.cert_off is not None
b64 = base64.b64encode(cert)
if len(b64) != self.cert_len:
@@ -256,7 +256,7 @@ class Envelope:
self.raw[self.cert_off : self.cert_off + self.cert_len] = b64
return self
def patch_session(self, session: int) -> "Envelope":
def patch_session(self, session: int) -> Envelope:
if self.tag4_span:
struct.pack_into(">I", self.raw, self.tag4_span[0], session & 0xFFFFFFFF)
d = self.raw
+3 -8
View File
@@ -3,6 +3,7 @@ TAF/WUP 帧解码器 — 将二进制帧转为可读摘要,用于日志输出
"""
from typing import Any, cast
from .taf_protocol import TafInputStream, TafType
from .wup_protocol import normalize_wup_payload
@@ -103,7 +104,7 @@ def _decode_taf_struct(ins: TafInputStream, depth: int = 0) -> dict:
except Exception:
val = f"<decode_err:0x{dtype:02x}>"
else:
val = f"<...>"
val = "<...>"
try:
ins.skip_field(dtype)
except Exception:
@@ -152,13 +153,7 @@ def _decode_wup_body(body: bytes) -> dict:
if tag > 10:
break
ins.read_head()
if tag == 1:
if dtype != TafType.ZERO:
ins._read_int_value(dtype)
elif tag in (2, 3):
if dtype != TafType.ZERO:
ins._read_int_value(dtype)
elif tag == 4:
if tag == 1 or tag in (2, 3) or tag == 4:
if dtype != TafType.ZERO:
ins._read_int_value(dtype)
elif tag == 5:
+7 -7
View File
@@ -11,13 +11,13 @@ import base64
import hashlib
import json
import random
import struct
import urllib.parse
import urllib.request
from typing import Any, Optional, Callable
from collections.abc import Callable
from typing import Any
from .cookie_utils import cookie_pairs, normalize_cookie_pairs, normalize_huya_cookie
from .taf_protocol import TafOutputStream, TafInputStream, TafType, TafStruct
from .taf_protocol import TafInputStream, TafOutputStream, TafStruct
from .wup_protocol import WupRequest, WupResponse
CDNWS_HOST = "cdnws.api.huya.com"
@@ -849,11 +849,11 @@ class HuyaHttpClient:
):
"""order_type=None 时自动尝试从 1 到 10 找到有效值"""
from .shop_structs import (
CreateOrderReqV5,
CreateOrderRsp,
CreateOrderAccountParam,
CreateOrderExtraParam,
CreateOrderPromotionParam,
CreateOrderAccountParam,
CreateOrderReqV5,
CreateOrderRsp,
)
# 如果指定了具体值,直接试
@@ -951,7 +951,7 @@ class HuyaHttpClient:
baseinfo = self._generate_rpc_baseinfo(uid, guid, cookie)
url = f"https://{CDNWS_HOST}/?baseinfo={baseinfo}"
self.logger(f"[HTTP] POST shopMiddleUI.payOrderSubmitV5")
self.logger("[HTTP] POST shopMiddleUI.payOrderSubmitV5")
self.logger(f"[HTTP] 发送 hex前60: {wup_data[:60].hex()}")
req = urllib.request.Request(
+2 -3
View File
@@ -14,12 +14,11 @@ from http.cookies import SimpleCookie
from urllib.parse import quote, urlsplit, urlunsplit
import requests
from requests.cookies import RequestsCookieJar
from loguru import logger
from requests.cookies import RequestsCookieJar
from .cookie_utils import normalize_huya_cookie
APP_ID = "5002"
APP_VERSION = "2.6"
APP_SIGN = "1ce3bf682483d03f146f58232ec10635"
@@ -101,7 +100,7 @@ def generate_context(device_id: str | None = None, mid: str | None = None) -> st
def generate_request_id() -> str:
"""生成 requestId,形态参考旧实现的日内毫秒数。"""
now = dt.datetime.now(dt.timezone.utc)
now = dt.datetime.now(dt.UTC)
midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
return str(int((now - midnight).total_seconds() * 1000))
+14 -14
View File
@@ -5,8 +5,8 @@
来源:m-shop.yaoguo.com 的 jce/ShopFacade.js、api/orderui.ts、api/mall/PlayMallNewHome.ts
"""
from typing import List, Dict, Optional
from .taf_protocol import TafOutputStream, TafInputStream, TafStruct, TafType
from .taf_protocol import TafInputStream, TafOutputStream, TafStruct, TafType
class OrderType:
@@ -387,7 +387,7 @@ class GoodsPriceInfo(TafStruct):
self.spuId: str = ""
self.minPrice: int = 0
self.maxPrice: int = 0
self.skuMap: Dict[int, GoodsSkuItem] = {}
self.skuMap: dict[int, GoodsSkuItem] = {}
self.stock: int = 0
self.buyLimit: int = 0
self.price: int = 0
@@ -500,7 +500,7 @@ class OrderListGoodsDetail(TafStruct):
self.buyerUid: int = 0 # tag 18
self.virtualType: int = 0 # tag 19
self.quantity: int = 0 # tag 20
self.shopInfo: Optional[OrderListShopInfo] = None # tag 21
self.shopInfo: OrderListShopInfo | None = None # tag 21
self.points: int = 0 # tag 23
def read_from(self, ins: TafInputStream):
@@ -544,7 +544,7 @@ class OrderListItem(TafStruct):
self.totalPrice: int = 0 # tag 12 分
self.createTime: int = 0 # tag 14 毫秒时间戳
self.payTime: int = 0 # tag 15 毫秒时间戳
self.goodsDetail: Optional[OrderListGoodsDetail] = None # tag 16
self.goodsDetail: OrderListGoodsDetail | None = None # tag 16
def read_from(self, ins: TafInputStream):
self.bizOrderId = ins.read_string(0, default=self.bizOrderId)
@@ -611,7 +611,7 @@ class QueryUserOrderListRsp(TafStruct):
self.code: int = 0
self.message: str = ""
self.totalCount: int = 0
self.orders: List[OrderListItem] = []
self.orders: list[OrderListItem] = []
@staticmethod
def _read_order_item(ins: TafInputStream, _tag: int):
@@ -692,9 +692,9 @@ class CreateOrderPromotionParam(TafStruct):
class CreateOrderAccountParam(TafStruct):
def __init__(self):
self.payoutTypeList: List[int] = [] # tag 0 Vector<INT32>
self.payoutTypeList: list[int] = [] # tag 0 Vector<INT32>
self.payoutChargeAmount: int = 0 # tag 1
self.cancelPayoutTypeList: List[int] = [] # tag 2
self.cancelPayoutTypeList: list[int] = [] # tag 2
self.recycleSupplierId: int = 0 # tag 3
self.claimPrice: int = 0 # tag 4
@@ -739,20 +739,20 @@ class CreateOrderReqV5(TafStruct):
self.gameId: str = "" # tag 8
self.orderId: int = 0 # tag 9
self.src: int = 0 # tag 10
self.couponUserIds: List[int] = [] # tag 11 Vector<INT64>
self.couponUserIds: list[int] = [] # tag 11 Vector<INT64>
self.orderType: int = 0 # tag 12
self.extraParam: Optional[CreateOrderExtraParam] = None # tag 13
self.extraParam: CreateOrderExtraParam | None = None # tag 13
self.scene: int = 0 # tag 14
self.promotionItems: List = [] # tag 15 Vector<PromotionItem>
self.promotionItems: list = [] # tag 15 Vector<PromotionItem>
self.sourceId: str = "" # tag 16
self.env: Dict[str, str] = {} # tag 17 Map<STRING,STRING>
self.env: dict[str, str] = {} # tag 17 Map<STRING,STRING>
self.orderScene: int = 0 # tag 18
self.watchWord: str = "" # tag 19
self.marketingChannel: str = "" # tag 20
self.promotionParam: Optional[CreateOrderPromotionParam] = None # tag 21
self.promotionParam: CreateOrderPromotionParam | None = None # tag 21
self.externalTraceKey: str = "" # tag 22
self.kefuUid: int = 0 # tag 23
self.accountParam: Optional[CreateOrderAccountParam] = None # tag 24
self.accountParam: CreateOrderAccountParam | None = None # tag 24
self.parentOrderId: int = 0 # tag 25
self.vendorAccountType: str = "" # tag 26
self.vendorAccountVal: str = "" # tag 27
+1 -2
View File
@@ -29,7 +29,6 @@ from .login import (
generate_request_id,
)
SMS_CODE_URI = "60027"
SMS_LOGIN_URI = "60025"
SMS_CODE_URL = "https://udblgn.huya.com/web/v2/smsCode"
@@ -604,7 +603,7 @@ class HuyaSmsLogin:
phone: str = "",
proxies: Mapping[str, str] | None = None,
timeout: tuple[float, float] | None = None,
) -> "HuyaSmsLogin":
) -> HuyaSmsLogin:
"""从发码阶段返回的 state 恢复短信登录会话。"""
try:
raw = base64.urlsafe_b64decode(state.encode("ascii"))
+10 -10
View File
@@ -9,9 +9,9 @@
0x0c ZERO 0x0d SIMPLE_LIST
"""
import struct
import io
from typing import Any, Dict, List, Optional, Tuple
import struct
from typing import Any
class TafType:
@@ -136,7 +136,7 @@ class TafOutputStream:
# ---- Map ----
def write_map(
self, tag: int, value: Dict[Any, Any], key_writer=None, val_writer=None
self, tag: int, value: dict[Any, Any], key_writer=None, val_writer=None
):
self.write_head(tag, TafType.MAP)
self.write_int32(0, len(value))
@@ -151,7 +151,7 @@ class TafOutputStream:
self._write_any(1, v)
# ---- List ----
def write_list(self, tag: int, value: List[Any], item_writer=None):
def write_list(self, tag: int, value: list[Any], item_writer=None):
self.write_head(tag, TafType.LIST)
self.write_int32(0, len(value))
for item in value:
@@ -192,7 +192,7 @@ class TafInputStream:
def __init__(self, data: bytes):
self.buf = io.BytesIO(data)
def peek_head(self) -> Tuple[int, int]:
def peek_head(self) -> tuple[int, int]:
"""读取 head 但不消费(用于探测)"""
pos = self.buf.tell()
try:
@@ -200,7 +200,7 @@ class TafInputStream:
finally:
self.buf.seek(pos)
def read_head(self) -> Tuple[int, int]:
def read_head(self) -> tuple[int, int]:
"""返回 (tag, type)"""
data = self.buf.read(1)
if not data:
@@ -293,7 +293,7 @@ class TafInputStream:
self.skip_field(it)
# ---- 带跳过策略的字段读取:找到 tag,否则返回默认 ----
def _find_tag(self, target_tag: int, required: bool) -> Optional[Tuple[int, int]]:
def _find_tag(self, target_tag: int, required: bool) -> tuple[int, int] | None:
"""逐个读 head,tag 相等则返回,tag 超过则回退并返回 None"""
while True:
pos = self.buf.tell()
@@ -402,7 +402,7 @@ class TafInputStream:
# ---- 复合类型 ----
def read_map(
self, tag: int, required: bool = False, key_reader=None, val_reader=None
) -> Dict:
) -> dict:
found = self._find_tag(tag, required)
if not found:
return {}
@@ -418,7 +418,7 @@ class TafInputStream:
result[k] = v
return result
def read_list(self, tag: int, required: bool = False, item_reader=None) -> List:
def read_list(self, tag: int, required: bool = False, item_reader=None) -> list:
found = self._find_tag(tag, required)
if not found:
return []
@@ -486,7 +486,7 @@ class TafStruct:
def read_from(self, ins: TafInputStream):
raise NotImplementedError
def to_dict(self) -> Dict[str, Any]:
def to_dict(self) -> dict[str, Any]:
"""调试用:转字典"""
return {k: v for k, v in self.__dict__.items() if not k.startswith("_")}
-1
View File
@@ -13,7 +13,6 @@ import onnxruntime as ort
from PIL import Image
from scipy.optimize import linear_sum_assignment
MODEL_DIR = Path(__file__).resolve().parent / "models"
+1 -2
View File
@@ -17,13 +17,12 @@ import cv2
import execjs
import numpy as np
import requests
from PIL import Image
from loguru import logger
from PIL import Image
from .ocr import HuyaCaptchaOcr, default_ocr
from .track import format_track, generate_slide_track
DEFAULT_UA = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
+12 -12
View File
@@ -21,14 +21,14 @@ import re
import struct
import time
from collections import deque
from typing import Any, Optional, Callable, cast
from collections.abc import Callable
from typing import Any, cast
import websockets
from .frame_decoder import _decode_taf_struct, _truncate, format_wss_log
from .taf_protocol import TafInputStream, TafOutputStream, TafStruct, TafType
from .wup_protocol import WupRequest, WupResponse
from .taf_protocol import TafOutputStream, TafInputStream, TafType, TafStruct
from .frame_decoder import format_wss_log, _decode_taf_struct, _truncate
SHOP_WS_HOST = "77bc035c-ws.va.huya.com"
# 商城端点 baseinfo (conn4, h5_/index.html) — 商城业务 shopMiddleUI 走此通道
@@ -225,7 +225,7 @@ class HuyaWssClient:
),
timeout=timeout,
)
except asyncio.TimeoutError:
except TimeoutError:
self.logger(f"[WSS] 连接超时({timeout}s")
raise
except Exception as e:
@@ -376,7 +376,7 @@ class HuyaWssClient:
try:
body = await asyncio.wait_for(future, timeout)
except asyncio.TimeoutError:
except TimeoutError:
if future in self.rpc_queue:
self.rpc_queue.remove(future)
self.logger("[✗] wsLaunch 超时")
@@ -526,7 +526,7 @@ class HuyaWssClient:
try:
body = await asyncio.wait_for(future, timeout)
except asyncio.TimeoutError:
except TimeoutError:
if future in self.rpc_queue:
self.rpc_queue.remove(future)
self.logger("[✗] getConfig 超时")
@@ -596,7 +596,7 @@ class HuyaWssClient:
try:
body = await asyncio.wait_for(future, timeout)
except asyncio.TimeoutError:
except TimeoutError:
if future in self.rpc_queue:
self.rpc_queue.remove(future)
self.logger(f"[✗] {service}.{method} 超时")
@@ -696,11 +696,11 @@ class HuyaWssClient:
order_type: int = 6,
):
from .shop_structs import (
CreateOrderReqV5,
CreateOrderRsp,
CreateOrderAccountParam,
CreateOrderExtraParam,
CreateOrderPromotionParam,
CreateOrderAccountParam,
CreateOrderReqV5,
CreateOrderRsp,
)
req = CreateOrderReqV5()
@@ -781,7 +781,7 @@ class HuyaWssClient:
try:
body = await asyncio.wait_for(future, 15.0)
except asyncio.TimeoutError:
except TimeoutError:
if future in self.rpc_queue:
self.rpc_queue.remove(future)
self.logger("[✗] payOrderSubmitV5 超时")
+4 -4
View File
@@ -9,7 +9,7 @@ import json
import random
import struct
import time as _time
from typing import Any, Dict
from typing import Any
# TAF 类型标签
INT8, INT16, INT32, INT64 = 0x00, 0x01, 0x02, 0x03
@@ -97,7 +97,7 @@ class _Writer:
def _build_meta_json(session: int, trace_id: str) -> str:
"""构造 _wup_data.t0.t2 元数据 JSON。"""
meta: Dict[str, Any] = {
meta: dict[str, Any] = {
"associationId": 8193,
"funcName": "hypasswordLogin",
"group": 1,
@@ -167,7 +167,7 @@ def _build_wup_data(
session: int,
trace_id: str,
user_action_json: str,
device_info: Dict[str, str],
device_info: dict[str, str],
) -> None:
"""编码 _wup_data struct。"""
meta_json = _build_meta_json(session, trace_id)
@@ -235,7 +235,7 @@ def build_password_login_wup(
session: int,
trace_id: str,
user_action_json: str,
device_info: Dict[str, str],
device_info: dict[str, str],
) -> bytes:
"""构造密码登录的 WUP TAF 请求体。"""
wd = _Writer()
+10 -9
View File
@@ -11,8 +11,9 @@ Wup 包结构:
"""
import struct
from typing import Any, Dict, Optional
from .taf_protocol import TafOutputStream, TafInputStream, TafType, TafStruct
from typing import Any
from .taf_protocol import TafInputStream, TafOutputStream, TafStruct, TafType
class WupRequest:
@@ -27,9 +28,9 @@ class WupRequest:
self.sFuncName: str = "" # tag 6
self.sBuffer: bytes = b"" # tag 7
self.iTimeout: int = 3000 # tag 8
self.context: Dict[str, str] = {} # tag 9
self.status: Dict[str, str] = {} # tag 10
self.newdata: Dict[str, bytes] = {}
self.context: dict[str, str] = {} # tag 9
self.status: dict[str, str] = {} # tag 10
self.newdata: dict[str, bytes] = {}
def setServant(self, name: str):
self.sServantName = name
@@ -141,9 +142,9 @@ class WupResponse:
self.sFuncName: str = ""
self.sBuffer: bytes = b""
self.iTimeout: int = 0
self.context: Dict[str, str] = {}
self.status: Dict[str, str] = {}
self.newdata: Dict[str, bytes] = {}
self.context: dict[str, str] = {}
self.status: dict[str, str] = {}
self.newdata: dict[str, bytes] = {}
def decode(self, data: bytes):
"""解码响应(不包含长度前缀;若含前缀会自动跳过)"""
@@ -269,7 +270,7 @@ def _read_bytes_value(ins: TafInputStream, dtype: int) -> bytes:
return ins.buf.read(length)
def _read_map_value(ins: TafInputStream, dtype: int) -> Dict:
def _read_map_value(ins: TafInputStream, dtype: int) -> dict:
if dtype != TafType.MAP:
return {}
count = ins._read_int_len()