diff --git a/client.py b/client.py index 9477f4b..2e82f8f 100644 --- a/client.py +++ b/client.py @@ -17,6 +17,10 @@ class Client(ClientBase): match action: case SendOps.LOGIN_PASSWORD: self._loop.create_task(self.do_login()) + case _: + ... + + await sleep(0.5) @packet_handler(RecvOps.PING) async def pong(self, ipkt): @@ -29,4 +33,5 @@ class Client(ClientBase): opkt = oPacket(SendOps.LOGIN_PASSWORD) opkt.encode_string(self._username) opkt.encode_string(self._password) + print(f"Sending login request") await self.send_packet(opkt) \ No newline at end of file diff --git a/client_base.py b/client_base.py index 3552078..24fb13c 100644 --- a/client_base.py +++ b/client_base.py @@ -1,9 +1,15 @@ -from asyncio import Event, get_event_loop, get_running_loop, run_coroutine_threadsafe, sleep, Lock, Queue, Task +from asyncio import ( + Event, Lock, Queue, Task, get_event_loop, get_running_loop, + run_coroutine_threadsafe, sleep +) from socket import AF_INET, IPPROTO_TCP, SOCK_STREAM, TCP_NODELAY, socket -from .packet import PacketHandler, Packet, iPacket, oPacket -from .crypto import MapleAes, decrypt_transform, encrypt_transform, MapleIV + from rich import print +from .crypto import MapleAes, MapleIV, decrypt_transform, encrypt_transform +from .opcodes import SendOps +from .packet import PacketHandler, iPacket, oPacket + class ClientBase: @@ -19,8 +25,8 @@ class ClientBase: self._version = None self._sub_version = None self._locale = None - self._recv_iv: MapleIV | None = None - self._send_iv: MapleIV | None = None + self._recv_iv: MapleIV = None # type: ignore + self._send_iv: MapleIV = None # type: ignore self._buff = bytearray() self._recv_task = None self.add_packet_handlers() @@ -39,12 +45,24 @@ class ClientBase: opkt = bytearray(opacket.getvalue()) length = len(opkt) - # buf = memoryview(opkt) - header = MapleAes.get_header(self._send_iv, length, self._version) - encrypt_transform(opkt) - opkt = MapleAes.transform(opkt, self._send_iv) + buf = bytearray(length + 4) + buf[0:4] = self._send_iv.get_header(self._version, length) + opkt = encrypt_transform(opkt) + MapleAes.transform(opkt, self._send_iv) + buf[4:length + 4] = opkt + await self._loop.sock_sendall(self._sock, buf) - await self._loop.sock_sendall(self._sock, header + opkt) + def schedule_action(self, op_code, delay: None | float = 1.0): + + async def schd(): + if delay: + await sleep(delay) + if self._sock.fileno(): + await self._action_queue.put(op_code) + else: + raise ConnectionResetError + + return self._loop.create_task(schd()) async def _sock_recv(self): # 51.222.56.169 @@ -58,12 +76,13 @@ class ClientBase: while self._sock.fileno(): try: self._buff.extend( - (await self._loop.sock_recv(self._sock, nbytes))) + (await self._loop.sock_recv(self._sock, nbytes)) + ) except ConnectionResetError: print("Connection reset, attempting to reconnect..") self._create_sock() - self._send_iv = None - self._recv_iv = None + del self._send_iv + del self._recv_iv if self._action_task: self._action_task.cancel() self._action_queue = Queue() @@ -73,20 +92,27 @@ class ClientBase: begin_packet = iPacket(self._buff) op_code = 0x0E self._version = begin_packet.decode_short() - self._sub_version = begin_packet.decode_string() + self._sub_version = int(begin_packet.decode_string()) self._send_iv = MapleIV(begin_packet.decode_int()) self._recv_iv = MapleIV(begin_packet.decode_int()) self._locale = begin_packet.decode_byte() # print(begin_packet) self._action_task = self._loop.create_task( - getattr(self, "begin")()) + getattr(self, "begin")() + ) print( - f"Op Code: {op_code} [Client Hello] | Version: {self._version} | Sub Version: {self._sub_version} | Locale: {self._locale} | Send IV: {self._send_iv} | Recv IV: {self._recv_iv}" + f"Op Code: {op_code} [Client Hello] " + f"| Version: {self._version} " + f"| Sub Version: {self._sub_version} " + f"| Locale: {self._locale} " + f"| Send IV: {self._send_iv} " + f"| Recv IV: {self._recv_iv}" ) self._buff = bytearray() + self.schedule_action(SendOps.LOGIN_PASSWORD, 5.0) continue - if self._buff and len(self._buff) > 4: + if self._buff: length = MapleAes.get_length(self._buff[0:4]) if length != len(self._buff[4:length + 4]): @@ -140,4 +166,4 @@ class ClientBase: self._packet_handlers.append(member) async def begin(self): - raise NotImplementedError \ No newline at end of file + raise NotImplementedError diff --git a/crypto.py b/crypto.py index 4a9a97a..cc49e92 100644 --- a/crypto.py +++ b/crypto.py @@ -54,8 +54,8 @@ class MapleAes: @staticmethod def get_header(iv, length, major_ver): - first = -(major_ver + 1) ^ iv.hiword - second = (first + 2**16) ^ length + first = iv.hiword ^ major_ver + second = first ^ length return bytearray([ first & 0xFF, first >> 8 & 0xFF, second & 0xFF, second >> 8 & 0xFF ]) @@ -64,6 +64,10 @@ class MapleAes: def get_length(data): return ((data[1] << 8) + data[0]) ^ ((data[3] << 8) + data[2]) + @staticmethod + def encode_length(data): + return ((data[1] << 8) + data[0]) | ((data[3] << 8) + data[2]) + class MapleIV: _shuffle = bytearray([ @@ -108,6 +112,13 @@ class MapleIV: def loword(self): return self.value + def get_header(self, version, length): + first = self.hiword ^ version + second = first ^ length + return bytearray([ + first & 0xFF, first >> 8 & 0xFF, second & 0xFF, second >> 8 & 0xFF + ]) + def shuffle(self): seed = [0xF2, 0x53, 0x50, 0xC6] p_iv = self.value @@ -225,7 +236,7 @@ def encrypt_transform(data): length -= 1 i -= 1 - return bytearray([b[b_] for b_ in b]) + return bytearray([byte for byte in b.values()]) def roll_left(value, shift):