def test_get_remaining(self): dg = Datagram() dg.add_string16(b'test string') dg.add_uint32(2525) dgi = dg.iterator() self.assertEqual(dgi.remaining(), 2 + len('test string') + 4) self.assertEqual(dgi.get_remaining(), dg.get_message().tobytes())
def test_add_datagram(self): dg1 = Datagram() dg1.add_uint16(32) dg2 = Datagram() dg2.add_string16(b'hello') dg1.add_datagram(dg2) self.assertEqual(dg1.bytes(), struct.pack('<HH5B', 32, 5, *b'hello')) del dg2 self.assertEqual(dg1.bytes(), struct.pack('<HH5B', 32, 5, *b'hello'))
def disconnect(self, booted_index, booted_text): for task in self.tasks: task.cancel() del self.tasks[:] resp = Datagram() resp.add_uint16(CLIENT_GO_GET_LOST) resp.add_uint16(booted_index) resp.add_string16(booted_text.encode('utf-8')) self.transport.write(len(resp).to_bytes(2, byteorder='little')) self.transport.write(resp.bytes()) self.transport.close() self.service.log.debug( f'Booted client {self.channel} with index {booted_index} and text: "{booted_text}"' )
def receive_set_wishname(self, dgi): av_id = dgi.get_uint32() name = dgi.get_string16() av = self.get_potential_avatar(av_id) self.service.log.debug( f'Received wishname request from {self.channel} for avatar {av_id} for name "{name}".' ) pending = name.encode('utf-8') approved = b'' rejected = b'' failed = False resp = Datagram() resp.add_uint16(CLIENT_SET_WISHNAME_RESP) resp.add_uint32(av_id) resp.add_uint16(failed) resp.add_string16(pending) resp.add_string16(approved) resp.add_string16(rejected) self.send_datagram(resp) if av_id and av: dclass = self.service.dc_file.namespace['DistributedToon'] wishname_field = dclass['WishName'] wishname_state_field = dclass['WishNameState'] resp = Datagram() resp.add_server_header([DBSERVERS_CHANNEL], self.channel, DBSERVER_SET_STORED_VALUES) resp.add_uint32(av_id) resp.add_uint16(2) resp.add_uint16(wishname_state_field.number) wishname_state_field.pack_value(resp, ('PENDING', )) resp.add_uint16(wishname_field.number) wishname_field.pack_value(resp, (name, )) self.service.send_datagram(resp)
def receive_delete_avatar(self, dgi): av_id = dgi.get_uint32() av = self.get_potential_avatar(av_id) if not av: return self.potential_avatars[av.index] = None avatars = [ pot_av.do_id if pot_av else 0 for pot_av in self.potential_avatars ] self.avs_deleted.append((av_id, int(time.time()))) field = self.service.dc_file.namespace['Account']['ACCOUNT_AV_SET'] del_field = self.service.dc_file.namespace['Account'][ 'ACCOUNT_AV_SET_DEL'] dg = Datagram() dg.add_server_header([DBSERVERS_CHANNEL], self.channel, DBSERVER_SET_STORED_VALUES) dg.add_uint32(self.account.disl_id) dg.add_uint16(2) dg.add_uint16(field.number) field.pack_value(dg, avatars) dg.add_uint16(del_field.number) del_field.pack_value(dg, self.avs_deleted) self.service.send_datagram(dg) resp = Datagram() resp.add_uint16(CLIENT_DELETE_AVATAR_RESP) resp.add_uint8(0) # Return code av_count = sum( (1 if pot_av else 0 for pot_av in self.potential_avatars)) dg.add_uint16(av_count) for pot_av in self.potential_avatars: if not pot_av: continue dg.add_uint32(pot_av.do_id) dg.add_string16(pot_av.name.encode('utf-8')) dg.add_string16(pot_av.wish_name.encode('utf-8')) dg.add_string16(pot_av.approved_name.encode('utf-8')) dg.add_string16(pot_av.rejected_name.encode('utf-8')) dg.add_string16(pot_av.dna_string.encode('utf-8')) dg.add_uint8(pot_av.index) self.send_datagram(resp)
def test_add_data(self): s = 'hello_world'.encode('utf-8') dg = Datagram() dg.add_string16(s) other = struct.pack(f'<H{len(s)}b', len(s), *s) self.assertEqual(dg.bytes(), other) s = 'abcdefghijklmnop'.encode('utf-8') dg = Datagram() dg.add_string32(s) other = struct.pack(f'<I{len(s)}b', len(s), *s) self.assertEqual(dg.bytes(), other) dg.add_bytes(b'') self.assertEqual(dg.bytes(), other) dg = Datagram() dg.add_string16(b'') self.assertEqual(dg.bytes(), b'\x00\x00') dg = Datagram() random.seed('pydc') s = bytes(random.randint(0, 255) for _ in range((1 << 16))) with self.assertRaises(OverflowError): dg.add_string16(s) dg = Datagram() s = bytes(random.randint(0, 255) for _ in range((1 << 16))) dg.add_string32(s) s = b''.join((struct.pack('<I', len(s)), s)) self.assertEqual(dg.bytes(), s) dg = Datagram() dg.add_string32(b'') self.assertEqual(dg.bytes(), struct.pack('<I', 0)) dg = Datagram() c = chr(0x1F600).encode('utf-8') dg.add_bytes(c) self.assertEqual(dg.bytes(), c)
def receive_login(self, dgi): play_token = dgi.get_string16() server_version = dgi.get_string16() hash_val = dgi.get_uint32() want_magic_words = dgi.get_string16() self.service.log.debug( f'play_token:{play_token}, server_version:{server_version}, hash_val:{hash_val}, ' f'want_magic_words:{want_magic_words}') try: play_token = bytes.fromhex(play_token) nonce, tag, play_token = play_token[:16], play_token[ 16:32], play_token[32:] cipher = AES.new(CLIENTAGENT_SECRET, AES.MODE_EAX, nonce) data = cipher.decrypt_and_verify(play_token, tag) self.service.log.debug(f'Login token data:{data}') data = json.loads(data) for key in list(data.keys()): value = data[key] if type(value) == str: data[key] = value.encode('utf-8') self.account = DISLAccount(**data) except ValueError as e: self.disconnect(ClientDisconnect.LOGIN_ERROR, 'Invalid token') return self.channel = getClientSenderChannel(self.account.disl_id, 0) self.subscribe_channel(self.channel) self.subscribe_channel(getAccountChannel(self.account.disl_id)) resp = Datagram() resp.add_uint16(CLIENT_LOGIN_TOONTOWN_RESP) return_code = 0 # -13 == period expired resp.add_uint8(return_code) error_string = b'' # 'Bad DC Version Compare' resp.add_string16(error_string) resp.add_uint32(self.account.disl_id) resp.add_string16(self.account.username) account_name_approved = True resp.add_uint8(account_name_approved) resp.add_string16(self.account.whitelist_chat_enabled) resp.add_string16(self.account.create_friends_with_chat) resp.add_string16(self.account.chat_code_creation_rule) t = time.time() * 10e6 usecs = int(t % 10e6) secs = int(t / 10e6) resp.add_uint32(secs) resp.add_uint32(usecs) resp.add_string16(self.account.access) resp.add_string16(self.account.whitelist_chat_enabled) last_logged_in = time.strftime('%c') # time.strftime('%c') resp.add_string16(last_logged_in.encode('utf-8')) account_days = 0 resp.add_int32(account_days) resp.add_string16(self.account.account_type) resp.add_string16(self.account.username) self.send_datagram(resp)
def send_go_get_lost(self, booted_index, booted_text): resp = Datagram() resp.add_uint16(CLIENT_GO_GET_LOST) resp.add_uint16(booted_index) resp.add_string16(booted_text.encode('utf-8')) self.send_datagram(resp)