From 8ee0434d92f03c46f61baca8ba2aadd6617d1445 Mon Sep 17 00:00:00 2001 From: a1025 Date: Thu, 2 Jan 2025 02:20:22 +0800 Subject: [PATCH] feat(app): use custom appinfo --- lagrange/__init__.py | 23 +++++++++++--- lagrange/client/client.py | 2 +- lagrange/info/app.py | 63 +++++++++++++++++++++++++++++++++------ 3 files changed, 74 insertions(+), 14 deletions(-) diff --git a/lagrange/__init__.py b/lagrange/__init__.py index 47bf9da..7d01ffe 100644 --- a/lagrange/__init__.py +++ b/lagrange/__init__.py @@ -1,4 +1,8 @@ -from typing import Literal, Optional +import json +from typing import Optional + +from lagrange.info import AppInfo +from typing_extensions import Literal import asyncio from .client.client import Client as Client @@ -18,17 +22,19 @@ class Lagrange: def __init__( self, uin: int, - protocol: Literal["linux", "macos", "windows"] = "linux", + protocol: Literal["linux", "macos", "windows", "custom"] = "linux", sign_url: Optional[str] = None, device_info_path="./device.json", signinfo_path="./sig.bin", + custom_protocol_path="./protocol.json", ): self.im = InfoManager(uin, device_info_path, signinfo_path) self.uin = uin - self.info = app_list[protocol] self.sign = sign_provider(sign_url) if sign_url else None self.events = {} self.log = log + self._protocol = protocol + self._protocol_path = custom_protocol_path def subscribe(self, event, handler): self.events[event] = handler @@ -42,10 +48,19 @@ async def login(self, client: Client): return await client.login() async def run(self): + if self._protocol == "custom": + log.root.debug("load custom protocol from %s" % self._protocol_path) + with open(self._protocol_path, "r") as f: + proto = json.loads(f.read()) + app_info = AppInfo.load_custom(proto) + else: + app_info = app_list[self._protocol] + log.root.info(f"AppInfo: platform={app_info.os}, ver={app_info.build_version}({app_info.sub_app_id})") + with self.im as im: self.client = Client( self.uin, - self.info, + app_info, im.device, im.sig_info, self.sign, diff --git a/lagrange/client/client.py b/lagrange/client/client.py index 4060688..5a5a93e 100644 --- a/lagrange/client/client.py +++ b/lagrange/client/client.py @@ -191,7 +191,7 @@ async def _send_msg_raw(self, pb: dict, *, grp_id=0, uid="") -> SendMsgRsp: sendto[1] = {2: uid} elif grp_id: # grp sendto[2] = {1: grp_id} - elif uid and grp_id: # temp msg, untest + elif uid and grp_id: # temp msg, untested assert uid or grp_id, "uid and grp_id" sendto[3] = {1: grp_id, 2: uid} else: diff --git a/lagrange/info/app.py b/lagrange/info/app.py index 6ea99df..27cd3a7 100644 --- a/lagrange/info/app.py +++ b/lagrange/info/app.py @@ -1,9 +1,34 @@ +import re from dataclasses import dataclass -from typing import TypedDict +from typing import TypedDict, TypeVar, Union from .serialize import JsonSerializer +_T = TypeVar('_T', bound=dict[str, Union[int, str]]) +_trans_map = { + "SsoVersion": "pt_os_version", + "WtLoginSdk": "wtlogin_sdk", + "AppIdQrCode": "app_id_qrcode", + "MainSigMap": "main_sigmap", + "SubSigMap": "sub_sigmap", +} + +def _translate_appinfo(s: _T) -> _T: + out: _T = {} + for k, v in s.items(): + if k in _trans_map: + out[_trans_map[k]] = v + else: + k = re.sub( + r'([A-Z])([^A-Z]+)', + '_\g<0>', + k + ).lstrip("_").lower() + out[k] = v + return out + + @dataclass class AppInfo(JsonSerializer): os: str @@ -11,13 +36,12 @@ class AppInfo(JsonSerializer): vendor_os: str current_version: str - build_version: int + # build_version: int misc_bitmap: int pt_version: str pt_os_version: int package_name: str wtlogin_sdk: str - package_sign: str app_id: int sub_app_id: int app_id_qrcode: int @@ -26,6 +50,27 @@ class AppInfo(JsonSerializer): sub_sigmap: int nt_login_type: int + @property + def build_version(self) -> int: + return int(self.current_version.split("-")[1]) + + @property + def package_sign(self) -> str: + # QUA? + if self.os == "Windows": + kernel = "WIN" + elif self.os == "Linux": + kernel = "LNX" + elif self.os == "Mac": + kernel = "MAC" + else: + raise NotImplementedError(self.os) + return f"V1_{kernel}_NQ_{self.current_version}_RDM_B" + + @classmethod + def load_custom(cls, d: _T) -> "AppInfo": + return cls(**_translate_appinfo(d)) + class AppInfoDict(TypedDict): linux: AppInfo @@ -39,13 +84,13 @@ class AppInfoDict(TypedDict): kernel="Linux", vendor_os="linux", current_version="3.2.10-25765", - build_version=25765, + # build_version=25765, misc_bitmap=32764, pt_version="2.0.0", pt_os_version=19, package_name="com.tencent.qq", wtlogin_sdk="nt.wtlogin.0.0.1", - package_sign="V1_LNX_NQ_3.1.2-13107_RDM_B", + # package_sign="V1_LNX_NQ_3.1.2-13107_RDM_B", app_id=1600001615, sub_app_id=537234773, app_id_qrcode=13697054, @@ -59,13 +104,13 @@ class AppInfoDict(TypedDict): kernel="Darwin", vendor_os="mac", current_version="6.9.20-17153", - build_version=17153, + # build_version=17153, misc_bitmap=32764, pt_version="2.0.0", pt_os_version=23, package_name="com.tencent.qq", wtlogin_sdk="nt.wtlogin.0.0.1", - package_sign="V1_MAC_NQ_6.9.20-17153_RDM_B", + # package_sign="V1_MAC_NQ_6.9.20-17153_RDM_B", app_id=1600001602, sub_app_id=537162356, app_id_qrcode=537162356, @@ -79,13 +124,13 @@ class AppInfoDict(TypedDict): kernel="Windows_NT", vendor_os="win32", current_version="9.9.2-15962", - build_version=15962, + # build_version=15962, pt_version="2.0.0", misc_bitmap=32764, pt_os_version=23, package_name="com.tencent.qq", wtlogin_sdk="nt.wtlogin.0.0.1", - package_sign="V1_WIN_NQ_9.9.2-15962_RDM_B", + # package_sign="V1_WIN_NQ_9.9.2-15962_RDM_B", app_id=1600001604, sub_app_id=537138217, app_id_qrcode=537138217,