def encode_register( seq: int, session_id: bytes, ksid: bytes, uin: int, tgt: bytes, d2: bytes, d2key: bytes, status: Union[int, OnlineStatus], reg_push_reason: Union[str, RegPushReason], ) -> Packet: """Build status service register packet. Called in ``com.tencent.mobileqq.msf.core.push.e.a``. command name: ``StatSvc.register`` Note: Source: com.tencent.mobileqq.msf.core.push.e.a Args: seq (int): Packet sequence. session_id (bytes): Session ID. ksid (bytes): KSID of client. uin (int): User QQ number. tgt (bytes): Siginfo tgt. d2 (bytes): Siginfo d2. d2key (bytes): Siginfo d2 key. status (Union[int, OnlineStatus]): Online status. reg_push_reason (Union[str, RegPushReason]): Reg push reason. battery_status (Optional[int], optional): Battery capacity. Defaults to None. is_power_connected (bool, optional): Is power connected to phone. Defaults to False. Returns: Packet: Register packet. """ COMMAND_NAME = "StatSvc.register" SUB_APP_ID = APK_INFO.sub_app_id svc = _encode_svc_request(uin, status, reg_push_reason) payload = SvcReqRegister.to_bytes(0, svc) req_packet = RequestPacketVersion3( servant_name="PushService", func_name="SvcReqRegister", data=types.MAP({types.STRING("SvcReqRegister"): types.BYTES(payload)}), ).encode() sso_packet = CSsoBodyPacket.build( seq, SUB_APP_ID, COMMAND_NAME, DEVICE.imei, session_id, ksid, body=req_packet, extra_data=tgt, ) packet = CSsoDataPacket.build(uin, 1, sso_packet, key=d2key, extra_data=d2) return packet
def encode_force_offline_response( seq: int, session_id: bytes, ksid: bytes, uin: int, tgt: bytes, d2: bytes, d2key: bytes, req_uin: int, seq_no: int, ) -> Packet: """Build status service msf offline response packet. Called in ``com.tencent.mobileqq.msf.core.af.a``. command name: ``StatSvc.RspMSFForceOffline`` Note: Source: com.tencent.mobileqq.msf.core.af.a Args: seq (int): Packet sequence. session_id (bytes): Session ID. ksid (bytes): KSID of client. uin (int): User QQ number. tgt (bytes): Siginfo tgt. d2 (bytes): Siginfo d2. d2key (bytes): Siginfo d2 key. req_uin (int): Request offline uin. seq_no (int): Request sequence number. Returns: Packet: msf force offline response packet. """ COMMAND_NAME = "StatSvc.RspMSFForceOffline" SUB_APP_ID = APK_INFO.sub_app_id resp = ResponseMSFForceOffline(uin=req_uin, seq_no=seq_no, c=bytes(1)) payload = ResponseMSFForceOffline.to_bytes(0, resp) resp_packet = RequestPacketVersion3( servant_name="StatSvc", func_name="RspMSFForceOffline", data=types.MAP( {types.STRING("RspMSFForceOffline"): types.BYTES(payload)} ), ).encode() sso_packet = CSsoBodyPacket.build( seq, SUB_APP_ID, COMMAND_NAME, DEVICE.imei, session_id, ksid, body=resp_packet, extra_data=tgt, ) packet = CSsoDataPacket.build(uin, 1, sso_packet, key=d2key, extra_data=d2) return packet
def encode_set_status( seq: int, session_id: bytes, uin: int, d2key: bytes, status: Union[int, OnlineStatus], battery_status: Optional[int] = None, is_power_connected: bool = False, ) -> Packet: """Build status service register packet. Called in ``com.tencent.mobileqq.msf.core.push.e.a``. command name: ``StatSvc.SetStatusFromClient`` Note: Source: com.tencent.mobileqq.msf.core.push.e.a Args: seq (int): Packet sequence. session_id (bytes): Session ID. uin (int): User QQ number. d2key (bytes): Siginfo d2 key. status (Union[int, OnlineStatus]): Online status. reg_push_reason (Union[str, RegPushReason]): Reg push reason. battery_status (Optional[int], optional): Battery capacity. Only works when status is :obj:`.OnlineStatus.Battery`. Defaults to None. is_power_connected (bool, optional): Is power connected to phone. Only works when status is :obj:`.OnlineStatus.Battery`. Defaults to False. Returns: Packet: Register packet. """ COMMAND_NAME = "StatSvc.SetStatusFromClient" SUB_APP_ID = APK_INFO.sub_app_id svc = _encode_svc_request( uin, status, RegPushReason.SetOnlineStatus, ((status == OnlineStatus.Battery) or None) and battery_status, (status == OnlineStatus.Battery) and is_power_connected, ) payload = SvcReqRegister.to_bytes(0, svc) req_packet = RequestPacketVersion3( servant_name="PushService", func_name="SvcReqRegister", data=types.MAP({types.STRING("SvcReqRegister"): types.BYTES(payload)}), ).encode() packet = UniPacket.build( uin, seq, COMMAND_NAME, session_id, 1, req_packet, d2key ) return packet
def encode_get_troop_member_list( seq: int, session_id: bytes, uin: int, d2key: bytes, group_uin: int, group_code: int, next_uin: int = 0, ) -> Packet: """Build get troop member list packet. Called in ``com.tencent.mobileqq.troop.handler.TroopMemberInfoHandler.a``. command name: ``friendlist.GetTroopMemberListReq`` Note: Source: com.tencent.mobileqq.service.troop.TroopSender.c Args: seq (int): Packet sequence. session_id (bytes): Session ID. uin (int): User QQ number. d2key (bytes): Siginfo d2 key. group_uin (int): Group uin number. group_code (int): Group code number. next_uin (int, optional): Next uin number. Defaults to 0. Returns: Packet: getTroopMemberList simplified packet. """ COMMAND_NAME = "friendlist.GetTroopMemberListReq" req = TroopMemberListReq( uin=uin, group_code=group_code, next_uin=next_uin, group_uin=group_uin, version=3, ) payload = TroopMemberListReq.to_bytes(0, req) req_packet = RequestPacketVersion3( servant_name="mqq.IMService.FriendListServiceServantObj", func_name="GetTroopMemberListReq", data=types.MAP({types.STRING("GTML"): types.BYTES(payload)}), ).encode() packet = UniPacket.build(uin, seq, COMMAND_NAME, session_id, 1, req_packet, d2key) return packet
def test_map_encode(self): raw: Dict[types.JceType, types.JceType] = { types.STRING1("one"): types.STRING1("foo"), types.STRING1("two"): types.STRING1("bar") } encoded = bytes.fromhex("18 00 02 06 03 6F 6E 65 16 03 66 " "6F 6F 06 03 74 77 6F 16 03 62 61 72") self.assertEqual(types.MAP.to_bytes(1, raw), encoded) raw: Dict[types.JceType, types.JceType] = { types.STRING1("one"): types.MAP({types.STRING1("two"): types.BYTES("foo".encode())}) } encoded = bytes.fromhex("18 00 01 06 03 6F 6E 65 18 00 01 " "06 03 74 77 6F 1D 00 00 03 66 6F 6F") self.assertEqual(types.MAP.to_bytes(1, raw), encoded)
def encode_get_troop_list( seq: int, session_id: bytes, uin: int, d2key: bytes, cookies: Optional[bytes] = None, ) -> Packet: """Build get troop list v2 simplified packet. Called in ``com.tencent.mobileqq.troop.handler.TroopListHandler.a``. command name: ``friendlist.GetTroopListReqV2`` Note: Source: com.tencent.mobileqq.service.troop.TroopSender.b Args: seq (int): Packet sequence. session_id (bytes): Session ID. uin (int): User QQ number. d2key (bytes): Siginfo d2 key. cookies (Optional[bytes], optional): Cookie vector. Defaults to None. Returns: Packet: GetTroopListReqV2 simplified packet. """ COMMAND_NAME = "friendlist.GetTroopListReqV2" req = TroopListReqV2Simplify( uin=uin, get_msf_msg_flag=False, cookies=cookies, group_flag_ext=bytes([1]), version=9, version_num=1, get_long_group_name=True, ) payload = TroopListReqV2Simplify.to_bytes(0, req) req_packet = RequestPacketVersion3( servant_name="mqq.IMService.FriendListServiceServantObj", func_name="GetTroopListReqV2Simplify", data=types.MAP( {types.STRING("GetTroopListReqV2Simplify"): types.BYTES(payload)}), ).encode() packet = UniPacket.build(uin, seq, COMMAND_NAME, session_id, 1, req_packet, d2key) return packet
def test_map_decode(self): raw: Dict[types.JceType, types.JceType] = { types.STRING1("one"): types.STRING1("foo"), types.STRING1("two"): types.STRING1("bar") } encoded = bytes.fromhex("18 00 02 06 03 6F 6E 65 16 03 66 " "6F 6F 06 03 74 77 6F 16 03 62 61 72") _, decoded, _ = JceDecoder.decode_single(encoded) self.assertEqual(types.MAP.validate(decoded), raw) raw: Dict[types.JceType, types.JceType] = { types.STRING1("one"): types.MAP({types.STRING1("two"): types.BYTES("foo".encode())}) } encoded = bytes.fromhex("18 00 01 06 03 6F 6E 65 18 00 01 " "06 03 74 77 6F 1D 00 00 03 66 6F 6F") _, decoded, _ = JceDecoder.decode_single(encoded) self.assertEqual(types.MAP.validate(decoded), raw)
def encode_config_push_response( uin: int, seq: int, session_id: bytes, d2key: bytes, type: int, jcebuf: bytes, large_seq: int, ) -> Packet: """Build config push response packet. command name: ``ConfigPushSvc.PushResp`` Note: Source: com.tencent.mobileqq.msf.core.a.c.b Args: uin (int): User QQ number. seq (int): Packet sequence. session_id (bytes): Session ID. d2key (bytes): Siginfo d2 key. type (int): ConfigPushSvc request type. jcebuf (bytes): ConfigPushSvc request jcebuf. large_seq (int): ConfigPushSvc request large_seq. """ COMMAND_NAME = "ConfigPushSvc.PushResp" resp = PushResp(type=type, jcebuf=jcebuf if type == 3 else None, large_seq=large_seq) payload = PushResp.to_bytes(0, resp) resp_packet = RequestPacketVersion3( servant_name="QQService.ConfigPushSvc.MainServant", func_name="PushResp", data=types.MAP({types.STRING("PushResp"): types.BYTES(payload)}), ).encode() packet = UniPacket.build(uin, seq, COMMAND_NAME, session_id, 1, resp_packet, d2key) return packet
async def get_sso_list() -> SsoServerResponse: """Do sso server list request and return the response. Note: Source: com.tencent.mobileqq.msf.core.a.f.run Returns: SsoServerResponse: Sso server list response Raises: SsoServerException: Get sso server list failed. """ device = get_device() protocol = get_protocol() key = bytes([ 0xF0, 0x44, 0x1F, 0x5F, 0xF4, 0x2D, 0xA5, 0x8F, 0xDC, 0xF7, 0x94, 0x9A, 0xBA, 0x62, 0xD4, 0x11, ]) payload = SsoServerRequest.to_bytes( 0, SsoServerRequest(app_id=protocol.app_id, imei=device.imei)) req_packet = RequestPacketVersion3( servant_name="HttpServerListReq", func_name="HttpServerListReq", data=types.MAP( {types.STRING("HttpServerListReq"): types.BYTES(payload)}), ).encode(with_length=True) buffer: bytes = qqtea_encrypt(req_packet, key) async with connect("configsvr.msf.3g.qq.com", 443, ssl=True) as conn: query = (b"POST /configsvr/serverlist.jsp HTTP/1.1\r\n" b"Host: configsvr.msf.3g.qq.com\r\n" b"User-Agent: QQ/8.4.1.2703 CFNetwork/1126\r\n" b"Net-Type: Wifi\r\n" b"Accept: */*\r\n" b"Connection: close\r\n" b"Content-Type: application/octet-stream\r\n" b"Content-Length: " + str(len(buffer)).encode() + b"\r\n" b"\r\n" + buffer) conn.write(query) conn.write_eof() resp_bytes = await conn.read_all() response = http.client.HTTPResponse( _FakeSocket(resp_bytes) # type: ignore ) response.begin() if response.status != 200: raise SsoServerException( f"Get sso server list failed with response code {response.status}") data: bytes = qqtea_decrypt(response.read(), key) resp_packet = RequestPacketVersion3.decode(data) server_info = SsoServerResponse.decode( resp_packet.data["HttpServerListRes"][1:-1] # type: ignore ) return server_info
def encode_get_friend_list( seq: int, session_id: bytes, uin: int, d2key: bytes, friend_index: int = 0, friend_count: int = 0, group_index: int = 0, group_count: int = 0, ) -> Packet: """Build get friend list packet. Called in ``com.tencent.mobileqq.service.friendlist.FriendListService.k``. command name: ``friendlist.GetFriendListReq`` Note: Source: com.tencent.mobileqq.service.friendlist.FriendListService.m Args: seq (int): Packet sequence. session_id (bytes): Session ID. uin (int): User QQ number. d2key (bytes): Siginfo d2 key. friend_index (int): Start index of friend list. friend_count (int): Number of friends to list. group_index (int): Start index of group list. group_count (int): Number of groups to list. Returns: Packet: GetFriendListReq packet. """ COMMAND_NAME = "friendlist.GetFriendListReq" req = FriendListReq( request_type=3, if_reflush=friend_index <= 0, uin=uin, start_index=friend_index, friend_count=friend_count, group_id=bytes(1), if_get_group_info=group_count > 0, group_start_index=group_index, group_count=group_count, if_get_msf_group=False, if_show_term_type=True, version=31, d50_req=ReqBody( appid=1002, req_music_switch=1, req_mutualmark_alienation=1, req_ksing_switch=1, req_mutualmark_lbsshare=1, req_aio_quick_app=1, ).SerializeToString(), sns_type_list=[13580, 13581, 13582], ) payload = FriendListReq.to_bytes(0, req) req_packet = RequestPacketVersion3( servant_name="mqq.IMService.FriendListServiceServantObj", func_name="GetFriendListReq", data=types.MAP({types.STRING("FL"): types.BYTES(payload)}), ).encode() packet = UniPacket.build(uin, seq, COMMAND_NAME, session_id, 1, req_packet, d2key) return packet