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())
Beispiel #2
0
    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'))
Beispiel #3
0
 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}"'
     )
Beispiel #4
0
    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)
Beispiel #5
0
    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)
Beispiel #6
0
    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)
Beispiel #7
0
    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)
Beispiel #8
0
 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)