Exemple #1
0
class TestSendFile(TFCTestCase):

    def setUp(self) -> None:
        """Pre-test actions."""
        self.unit_test_dir = cd_unit_test()
        self.settings      = Settings()
        self.queues        = gen_queue_dict()
        self.window        = TxWindow()
        self.onion_service = OnionService()
        self.contact_list  = ContactList(nicks=['Alice', 'Bob', 'Charlie'])
        self.args          = self.settings, self.queues, self.window

    def tearDown(self) -> None:
        """Post-test actions."""
        cleanup(self.unit_test_dir)
        tear_queues(self.queues)

    def test_traffic_masking_raises_se(self) -> None:
        self.settings.traffic_masking = True
        self.assert_se("Error: Command is disabled during traffic masking.", send_file, "testfile.txt", *self.args)

    def test_missing_file_raises_se(self) -> None:
        self.assert_se("Error: File not found.", send_file, "testfile.txt", *self.args)

    def test_empty_file_raises_se(self) -> None:
        # Setup
        open('testfile.txt', 'wb+').close()

        # Test
        self.assert_se("Error: Target file is empty.", send_file, "testfile.txt", *self.args)

    @mock.patch('time.sleep', return_value=None)
    def test_file_transmission_to_contact(self, _: Any) -> None:
        # Setup
        self.window.window_contacts = [self.contact_list.get_contact_by_address_or_nick('Alice')]
        self.window.type_print      = 'contact'

        input_data = os.urandom(5)
        with open('testfile.txt', 'wb+') as f:
            f.write(input_data)

        # Test
        self.assertIsNone(send_file("testfile.txt", *self.args))
        self.assertEqual(self.queues[MESSAGE_PACKET_QUEUE].qsize(), 1)
        self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(),   1)

    @mock.patch('time.sleep', return_value=None)
    def test_file_transmission_to_group(self, _: Any) -> None:
        # Setup
        self.window.window_contacts = [self.contact_list.get_contact_by_address_or_nick('Alice'),
                                       self.contact_list.get_contact_by_address_or_nick('Bob')]
        self.window.type_print      = 'group'

        input_data = os.urandom(5)
        with open('testfile.txt', 'wb+') as f:
            f.write(input_data)

        self.assertIsNone(send_file("testfile.txt", *self.args))
        self.assertEqual(self.queues[MESSAGE_PACKET_QUEUE].qsize(), 2)
        self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(),   1)
Exemple #2
0
class TestChangeNick(TFCTestCase):

    def setUp(self) -> None:
        """Pre-test actions."""
        self.contact_list = ContactList(nicks=['Alice'])
        self.group_list   = GroupList()
        self.settings     = Settings()
        self.queues       = gen_queue_dict()
        self.args         = self.contact_list, self.group_list, self.settings, self.queues

    def tearDown(self) -> None:
        """Post-test actions."""
        tear_queues(self.queues)

    def test_missing_nick_raises_soft_error(self) -> None:
        self.assert_se("Error: No nick specified.",
                       change_nick, UserInput("nick "), TxWindow(type=WIN_TYPE_CONTACT), *self.args)

    def test_invalid_nick_raises_soft_error(self) -> None:
        # Setup
        window = TxWindow(type=WIN_TYPE_CONTACT,
                          contact=create_contact('Bob'))

        # Test
        self.assert_se("Error: Nick must be printable.",
                       change_nick, UserInput("nick Alice\x01"), window, *self.args)

    def test_no_contact_raises_soft_error(self) -> None:
        # Setup
        window = TxWindow(type=WIN_TYPE_CONTACT,
                          contact=create_contact('Bob'))
        window.contact = None

        # Test
        self.assert_se("Error: Window does not have contact.",
                       change_nick, UserInput("nick Alice\x01"), window, *self.args)

    def test_successful_nick_change(self) -> None:
        # Setup
        window = TxWindow(name='Alice',
                          type=WIN_TYPE_CONTACT,
                          contact=self.contact_list.get_contact_by_address_or_nick('Alice'))

        # Test
        self.assertIsNone(change_nick(UserInput("nick Alice_"), window, *self.args))
        self.assertEqual(self.contact_list.get_contact_by_pub_key(nick_to_pub_key('Alice')).nick, 'Alice_')

    @mock.patch('time.sleep', return_value=None)
    def test_successful_group_nick_change(self, _: Any) -> None:
        # Setup
        group      = create_group('test_group')
        user_input = UserInput("nick group2")
        window     = TxWindow(name ='test_group',
                              type =WIN_TYPE_GROUP,
                              group=group,
                              uid  =group.group_id)

        # Test
        self.assert_se("Renamed group 'test_group' to 'group2'.", change_nick, user_input, window, *self.args)
        self.assertEqual(window.group.name, 'group2')
Exemple #3
0
class TestPacketList(unittest.TestCase):

    def setUp(self):
        self.contact_list  = ContactList(nicks=['Alice', 'Bob'])
        self.settings      = Settings()
        self.onion_pub_key = nick_to_pub_key('Alice')
        packet             = Packet(self.onion_pub_key, ORIGIN_CONTACT_HEADER, MESSAGE,
                                    self.contact_list.get_contact_by_address_or_nick('Alice'), self.settings)

        self.packet_list         = PacketList(self.settings, self.contact_list)
        self.packet_list.packets = [packet]

    def test_packet_list_iterates_over_contact_objects(self):
        for p in self.packet_list:
            self.assertIsInstance(p, Packet)

    def test_len_returns_number_of_contacts(self):
        self.assertEqual(len(self.packet_list), 1)

    def test_has_packet(self):
        self.assertTrue(self.packet_list.has_packet(self.onion_pub_key, ORIGIN_CONTACT_HEADER, MESSAGE))
        self.assertFalse(self.packet_list.has_packet(self.onion_pub_key, ORIGIN_USER_HEADER, MESSAGE))

    def test_get_packet(self):
        packet = self.packet_list.get_packet(self.onion_pub_key, ORIGIN_CONTACT_HEADER, MESSAGE)
        self.assertEqual(packet.onion_pub_key, self.onion_pub_key)
        self.assertEqual(packet.origin, ORIGIN_CONTACT_HEADER)
        self.assertEqual(packet.type, MESSAGE)

        packet = self.packet_list.get_packet(self.onion_pub_key, ORIGIN_CONTACT_HEADER, MESSAGE)
        self.assertEqual(packet.onion_pub_key, self.onion_pub_key)
        self.assertEqual(packet.origin, ORIGIN_CONTACT_HEADER)
        self.assertEqual(packet.type, MESSAGE)
Exemple #4
0
    def test_loop(self):
        # Setup
        queues                 = gen_queue_dict()
        settings               = Settings(traffic_masking=True,
                                          tm_static_delay=0.001,
                                          tm_random_delay=0.001)
        gateway                = Gateway()
        key_list               = KeyList(nicks=['Alice', LOCAL_ID])
        window                 = TxWindow(log_messages=True)
        contact_list           = ContactList(nicks=['Alice', LOCAL_ID])
        window.contact_list    = contact_list
        window.window_contacts = [contact_list.get_contact_by_address_or_nick('Alice')]
        user_input             = UserInput(plaintext='test')

        def queue_delayer():
            """Place packets to queue after delay."""
            time.sleep(0.01)
            queues[WINDOW_SELECT_QUEUE].put(window.window_contacts)
            time.sleep(0.01)
            queue_command(b'test',            settings, queues)                                              # 1
            queue_message(user_input, window, settings, queues)                                              # 2
            queue_message(user_input, window, settings, queues)                                              # 3
            queue_command(b'test',            settings, queues)                                              # 4
            queues[TM_NOISE_COMMAND_QUEUE].put((C_N_HEADER + bytes(PADDING_LENGTH)))                         # 5
            queue_to_nc(UNENCRYPTED_DATAGRAM_HEADER + UNENCRYPTED_EXIT_COMMAND, queues[RELAY_PACKET_QUEUE])  # 6
            queue_to_nc(UNENCRYPTED_DATAGRAM_HEADER + UNENCRYPTED_WIPE_COMMAND, queues[RELAY_PACKET_QUEUE])  # 7
            queues[SENDER_MODE_QUEUE].put(settings)

        # Test
        threading.Thread(target=queue_delayer).start()
        self.assertIsInstance(traffic_masking_loop(queues, settings, gateway, key_list), Settings)
        self.assertEqual(len(gateway.packets), 7)

        # Teardown
        tear_queues(queues)
Exemple #5
0
class TestAddNewContact(TFCTestCase):

    def setUp(self) -> None:
        """Pre-test actions."""
        self.contact_list  = ContactList(nicks=[LOCAL_ID])
        self.group_list    = GroupList()
        self.settings      = Settings(disable_gui_dialog=True)
        self.queues        = gen_queue_dict()
        self.onion_service = OnionService()
        self.args          = self.contact_list, self.group_list, self.settings, self.queues, self.onion_service

    def tearDown(self) -> None:
        """Post-test actions."""
        with ignored(OSError):
            os.remove(f'v4dkh.psk - Give to hpcra')
        tear_queues(self.queues)

    def test_adding_new_contact_during_traffic_masking_raises_soft_error(self) -> None:
        # Setup
        self.settings.traffic_masking = True

        # Test
        self.assert_se("Error: Command is disabled during traffic masking.", add_new_contact, *self.args)

    def test_contact_list_full_raises_soft_error(self) -> None:
        # Setup
        contact_list               = ContactList(nicks=[str(n) for n in range(50)])
        self.contact_list.contacts = contact_list.contacts

        # Test
        self.assert_se("Error: TFC settings only allow 50 accounts.", add_new_contact, *self.args)

    @mock.patch('builtins.input', side_effect=[nick_to_onion_address("Bob"), 'Bob', '', VALID_ECDHE_PUB_KEY, 'Yes',
                                               blake2b(nick_to_pub_key('Bob'), digest_size=CONFIRM_CODE_LENGTH).hex()])
    @mock.patch('shutil.get_terminal_size', return_value=[200, 200])
    @mock.patch('time.sleep',               return_value=None)
    def test_default_nick_ecdhe(self, *_: Any) -> None:
        self.assertIsNone(add_new_contact(*self.args))
        contact = self.contact_list.get_contact_by_address_or_nick("Bob")
        self.assertEqual(contact.nick, 'Bob')
        self.assertNotEqual(contact.tx_fingerprint, bytes(FINGERPRINT_LENGTH))

    @mock.patch('src.transmitter.key_exchanges.ARGON2_PSK_MEMORY_COST',  200)
    @mock.patch('src.common.statics.MIN_KEY_DERIVATION_TIME', 0.1)
    @mock.patch('src.common.statics.MAX_KEY_DERIVATION_TIME', 1.0)
    @mock.patch('builtins.input',  side_effect=[nick_to_onion_address("Alice"), 'Alice_', 'psk', '.', '', 'ff', 'fc'])
    @mock.patch('getpass.getpass', return_value='test_password')
    @mock.patch('time.sleep',      return_value=None)
    def test_standard_nick_psk_kex(self, *_: Any) -> None:
        self.onion_service.account = nick_to_onion_address('Bob').encode()
        self.assertIsNone(add_new_contact(*self.args))
        contact = self.contact_list.get_contact_by_pub_key(nick_to_pub_key("Alice"))
        self.assertEqual(contact.nick, 'Alice_')
        self.assertEqual(contact.tx_fingerprint, bytes(FINGERPRINT_LENGTH))

    @mock.patch('time.sleep',     return_value=None)
    @mock.patch('builtins.input', side_effect=KeyboardInterrupt)
    def test_keyboard_interrupt_raises_soft_error(self, *_: Any) -> None:
        self.assert_se('Contact creation aborted.', add_new_contact, *self.args)
Exemple #6
0
class TestNewFile(TFCTestCase):

    def setUp(self) -> None:
        """Pre-test actions."""
        self.unit_test_dir = cd_unit_test()
        self.ts            = datetime.now()
        self.packet        = b''
        self.file_keys     = dict()
        self.file_buf      = dict()
        self.contact_list  = ContactList(nicks=['Alice'])
        self.window_list   = WindowList()
        self.file_key      = SYMMETRIC_KEY_LENGTH*b'a'
        self.settings      = Settings()
        self.compressed    = zlib.compress(str_to_bytes("test_file.txt") + b'file_data', level=COMPRESSION_LEVEL)
        self.args          = self.file_keys, self.file_buf, self.contact_list, self.window_list, self.settings

    def tearDown(self) -> None:
        """Post-test actions."""
        cleanup(self.unit_test_dir)

    def test_unknown_account_raises_soft_error(self) -> None:
        # Setup
        file_ct = encrypt_and_sign(self.compressed, self.file_key)
        packet  = nick_to_pub_key('Bob') + ORIGIN_CONTACT_HEADER + file_ct

        # Test
        self.assert_se("File from an unknown account.", new_file, self.ts, packet, *self.args)

    def test_disabled_file_reception_raises_soft_error(self) -> None:
        # Setup
        file_ct = encrypt_and_sign(self.compressed, self.file_key)
        packet  = nick_to_pub_key('Alice') + ORIGIN_CONTACT_HEADER + file_ct
        self.contact_list.get_contact_by_address_or_nick('Alice').file_reception = False

        # Test
        self.assert_se("Alert! Discarded file from Alice as file reception for them is disabled.",
                       new_file, self.ts, packet, *self.args)

    def test_valid_file_without_key_is_cached(self) -> None:
        # Setup
        file_ct   = encrypt_and_sign(self.compressed, self.file_key)
        file_hash = blake2b(file_ct)
        packet    = nick_to_pub_key('Alice') + ORIGIN_CONTACT_HEADER + file_ct

        # Test
        self.assertIsNone(new_file(self.ts, packet, *self.args))
        self.assertEqual(self.file_buf[nick_to_pub_key('Alice') + file_hash], (self.ts, file_ct))

    @mock.patch('time.sleep', return_value=None)
    def test_valid_file_with_key_is_processed(self, _: Any) -> None:
        # Setup
        file_ct        = encrypt_and_sign(self.compressed, self.file_key)
        file_hash      = blake2b(file_ct)
        packet         = nick_to_pub_key('Alice') + ORIGIN_CONTACT_HEADER + file_ct
        self.file_keys = {(nick_to_pub_key('Alice') + file_hash): self.file_key}
        self.args      = self.file_keys, self.file_buf, self.contact_list, self.window_list, self.settings

        # Test
        self.assertIsNone(new_file(self.ts, packet, *self.args))
Exemple #7
0
    def test_no_contact_found_on_transmitter(self, *_: Any) -> None:
        # Setup
        user_input   = UserInput(f'rm {nick_to_onion_address("Charlie")}')
        contact_list = ContactList(nicks=['Bob'])
        window       = TxWindow(window_contact=[contact_list.get_contact_by_address_or_nick('Bob')],
                                type=WIN_TYPE_GROUP)

        # Test
        self.assertIsNone(remove_contact(user_input, window, *self.args))
        self.assertEqual(self.queues[COMMAND_PACKET_QUEUE].qsize(), 1)
        self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(),   1)
        command_packet = self.queues[COMMAND_PACKET_QUEUE].get()
        self.assertIsInstance(command_packet, bytes)
Exemple #8
0
    def test_successful_removal(self):
        # Setup
        contact_list             = ContactList(nicks=['Alice', 'Bob'])
        contact                  = contact_list.get_contact_by_address_or_nick("Bob")
        group_list               = GroupList(groups=['test_group', 'test_group2'])
        key_list                 = KeyList(nicks=['Alice', 'Bob'])
        self.window_list.windows = [RxWindow(type=WIN_TYPE_GROUP)]

        # Test
        self.assert_fr("No log database available.",
                       contact_rem, *self.args, contact_list, group_list, key_list, self.settings, self.master_key)
        self.assertFalse(contact_list.has_pub_key(nick_to_pub_key("Bob")))
        self.assertFalse(key_list.has_keyset(nick_to_pub_key("Bob")))
        for g in group_list:
            self.assertFalse(contact in g.members)
Exemple #9
0
class TestVerify(TFCTestCase):
    def setUp(self):
        """Pre-test actions."""
        self.window = TxWindow(uid=nick_to_pub_key("Alice"),
                               name='Alice',
                               window_contacts=[create_contact('test_group')],
                               log_messages=True,
                               type=WIN_TYPE_CONTACT)
        self.contact_list = ContactList(nicks=['Alice'])
        self.contact = self.contact_list.get_contact_by_address_or_nick(
            'Alice')
        self.window.contact = self.contact
        self.args = self.window, self.contact_list

    def test_active_group_raises_fr(self):
        self.window.type = WIN_TYPE_GROUP
        self.assert_fr("Error: A group is selected.", verify, *self.args)

    def test_psk_raises_fr(self):
        self.contact.kex_status = KEX_STATUS_NO_RX_PSK
        self.assert_fr("Pre-shared keys have no fingerprints.", verify,
                       *self.args)

    @mock.patch('time.sleep', return_value=None)
    @mock.patch('builtins.input', side_effect=['No', 'Yes'])
    def test_fingerprint_check(self, *_):
        self.contact.kex_status = KEX_STATUS_VERIFIED

        self.assertIsNone(verify(*self.args))
        self.assertEqual(self.contact.kex_status, KEX_STATUS_UNVERIFIED)

        self.assertIsNone(verify(*self.args))
        self.assertEqual(self.contact.kex_status, KEX_STATUS_VERIFIED)

    @mock.patch('time.sleep', return_value=None)
    @mock.patch('builtins.input', side_effect=KeyboardInterrupt)
    def test_keyboard_interrupt_raises_fr(self, *_):
        self.contact.kex_status = KEX_STATUS_VERIFIED
        self.assert_fr("Fingerprint verification aborted.", verify, *self.args)
        self.assertEqual(self.contact.kex_status, KEX_STATUS_VERIFIED)
Exemple #10
0
class TestChContactSetting(TFCTestCase):

    def setUp(self):
        self.ts           = datetime.fromtimestamp(1502750000)
        self.contact_list = ContactList(nicks=['Alice', 'Bob'])
        self.group_list   = GroupList(groups=['test_group', 'test_group2'])
        self.window_list  = WindowList(contact_list=self.contact_list,
                                       group_list=self.group_list)
        self.args         = self.ts, self.window_list, self.contact_list, self.group_list

    def test_invalid_window_raises_fr(self):
        # Setup
        cmd_data          = ENABLE + nick_to_pub_key("Bob")
        header            = CH_LOGGING
        self.contact_list = ContactList(nicks=['Alice'])
        self.window_list  = WindowList(contact_list=self.contact_list,
                                       group_list=self.group_list)
        # Test
        self.assert_fr(f"Error: Found no window for '{nick_to_short_address('Bob')}'.",
                       ch_contact_s, cmd_data, *self.args, header)

    def test_setting_change_contact(self):
        # Setup
        self.window                 = self.window_list.get_window(nick_to_pub_key("Bob"))
        self.window.type            = WIN_TYPE_CONTACT
        self.window.type_print      = 'contact'
        self.window.window_contacts = self.contact_list.contacts
        bob                         = self.contact_list.get_contact_by_address_or_nick("Bob")

        # Test
        for attr, header in [('log_messages', CH_LOGGING),
                             ('notifications', CH_NOTIFY),
                             ('file_reception', CH_FILE_RECV)]:
            for s in [ENABLE, ENABLE, DISABLE, DISABLE]:
                cmd_data = s + nick_to_pub_key("Bob")
                self.assertIsNone(ch_contact_s(cmd_data, *self.args, header))
                self.assertEqual(bob.__getattribute__(attr), (s == ENABLE))

    def test_setting_change_group(self):
        # Setup
        self.window                 = self.window_list.get_window(group_name_to_group_id('test_group'))
        self.window.type            = WIN_TYPE_GROUP
        self.window.type_print      = 'group'
        self.window.window_contacts = self.group_list.get_group('test_group').members

        # Test
        for attr, header in [('log_messages', CH_LOGGING),
                             ('notifications', CH_NOTIFY),
                             ('file_reception', CH_FILE_RECV)]:
            for s in [ENABLE, ENABLE, DISABLE, DISABLE]:
                cmd_data = s + group_name_to_group_id('test_group')
                self.assertIsNone(ch_contact_s(cmd_data, *self.args, header))

                if header in [CH_LOGGING, CH_NOTIFY]:
                    self.assertEqual(self.group_list.get_group('test_group').__getattribute__(attr), (s == ENABLE))

                if header == CH_FILE_RECV:
                    for m in self.group_list.get_group('test_group').members:
                        self.assertEqual(m.file_reception, (s == ENABLE))

    def test_setting_change_all(self):
        # Setup
        self.window                 = self.window_list.get_window(nick_to_pub_key("Bob"))
        self.window.type            = WIN_TYPE_CONTACT
        self.window.type_print      = 'contact'
        self.window.window_contacts = self.contact_list.contacts

        # Test
        for attr, header in [('log_messages', CH_LOGGING),
                             ('notifications', CH_NOTIFY),
                             ('file_reception', CH_FILE_RECV)]:
            for s in [ENABLE, ENABLE, DISABLE, DISABLE]:
                cmd_data = s.upper() + US_BYTE
                self.assertIsNone(ch_contact_s(cmd_data, *self.args, header))

                if header in [CH_LOGGING, CH_NOTIFY]:
                    for c in self.contact_list.get_list_of_contacts():
                        self.assertEqual(c.__getattribute__(attr), (s == ENABLE))
                    for g in self.group_list.groups:
                        self.assertEqual(g.__getattribute__(attr), (s == ENABLE))

                if header == CH_FILE_RECV:
                    for c in self.contact_list.get_list_of_contacts():
                        self.assertEqual(c.__getattribute__(attr), (s == ENABLE))
Exemple #11
0
class TestContactSetting(TFCTestCase):

    def setUp(self) -> None:
        """Pre-test actions."""
        self.contact_list = ContactList(nicks=['Alice', 'Bob'])
        self.group_list   = GroupList(groups=['test_group'])
        self.settings     = Settings()
        self.queues       = gen_queue_dict()
        self.pub_key      = nick_to_pub_key("Alice")
        self.args         = self.contact_list, self.group_list, self.settings, self.queues

    def tearDown(self) -> None:
        """Post-test actions."""
        tear_queues(self.queues)

    def test_invalid_command_raises_soft_error(self) -> None:
        self.assert_se("Error: Invalid command.", contact_setting, UserInput('loging on'), None, *self.args)

    def test_missing_parameter_raises_soft_error(self) -> None:
        self.assert_se("Error: Invalid command.", contact_setting, UserInput(''), None, *self.args)

    def test_invalid_extra_parameter_raises_soft_error(self) -> None:
        self.assert_se("Error: Invalid command.", contact_setting, UserInput('logging on al'), None, *self.args)

    def test_enable_logging_for_user(self) -> None:
        # Setup
        contact              = self.contact_list.get_contact_by_address_or_nick('Alice')
        contact.log_messages = False
        window               = TxWindow(uid=self.pub_key,
                                        type=WIN_TYPE_CONTACT,
                                        contact=contact)

        # Test
        self.assertFalse(contact.log_messages)
        self.assertIsNone(contact_setting(UserInput('logging on'), window, *self.args))
        self.assertEqual(self.queues[COMMAND_PACKET_QUEUE].qsize(), 1)
        self.assertEqual(self.queues[LOG_SETTING_QUEUE].qsize(),    0)
        self.assertTrue(contact.log_messages)

    def test_enable_logging_for_user_during_traffic_masking(self) -> None:
        # Setup
        contact              = self.contact_list.get_contact_by_address_or_nick('Alice')
        contact.log_messages = False
        window               = TxWindow(uid=self.pub_key,
                                        type=WIN_TYPE_CONTACT,
                                        contact=contact,
                                        log_messages=False)
        self.settings.traffic_masking = True

        # Test
        self.assertFalse(contact.log_messages)
        self.assertFalse(window.log_messages)

        self.assertIsNone(contact_setting(UserInput('logging on'), window, *self.args))

        self.assertEqual(self.queues[TM_COMMAND_PACKET_QUEUE].qsize(), 1)
        self.assertTrue(self.queues[LOG_SETTING_QUEUE].get())
        self.assertTrue(window.log_messages)
        self.assertTrue(contact.log_messages)

    def test_enable_logging_for_group(self) -> None:
        # Setup
        group              = self.group_list.get_group('test_group')
        group.log_messages = False
        window             = TxWindow(uid=group_name_to_group_id('test_group'),
                                      type=WIN_TYPE_GROUP,
                                      group=group,
                                      window_contacts=group.members)

        # Test
        self.assertFalse(group.log_messages)
        self.assertIsNone(contact_setting(UserInput('logging on'), window, *self.args))
        self.assertTrue(group.log_messages)

    def test_enable_logging_for_all_users(self) -> None:
        # Setup
        contact = self.contact_list.get_contact_by_address_or_nick("Alice")
        window  = TxWindow(uid=self.pub_key,
                           type=WIN_TYPE_CONTACT,
                           contact=contact,
                           window_contacts=[contact])

        for c in self.contact_list:
            c.log_messages = False
        for g in self.group_list:
            g.log_messages = False

        # Test
        for c in self.contact_list:
            self.assertFalse(c.log_messages)
        for g in self.group_list:
            self.assertFalse(g.log_messages)

        self.assertIsNone(contact_setting(UserInput('logging on all'), window, *self.args))

        for c in self.contact_list:
            self.assertTrue(c.log_messages)
        for g in self.group_list:
            self.assertTrue(g.log_messages)

    def test_disable_logging_for_user(self) -> None:
        # Setup
        contact              = self.contact_list.get_contact_by_address_or_nick('Alice')
        contact.log_messages = True
        window               = TxWindow(uid=self.pub_key,
                                        type=WIN_TYPE_CONTACT,
                                        contact=contact,
                                        window_contacts=[contact])

        # Test
        self.assertTrue(contact.log_messages)
        self.assertIsNone(contact_setting(UserInput('logging off'), window, *self.args))
        self.assertFalse(contact.log_messages)

    def test_disable_logging_for_group(self) -> None:
        # Setup
        group              = self.group_list.get_group('test_group')
        group.log_messages = True
        window             = TxWindow(uid=group_name_to_group_id('test_group'),
                                      type=WIN_TYPE_GROUP,
                                      group=group,
                                      window_contacts=group.members)

        # Test
        self.assertTrue(group.log_messages)
        self.assertIsNone(contact_setting(UserInput('logging off'), window, *self.args))
        self.assertFalse(group.log_messages)

    def test_disable_logging_for_all_users(self) -> None:
        # Setup
        contact = self.contact_list.get_contact_by_address_or_nick("Alice")
        window  = TxWindow(uid=self.pub_key,
                           type=WIN_TYPE_CONTACT,
                           contact=contact,
                           window_contacts=[contact])

        for c in self.contact_list:
            c.log_messages = True
        for g in self.group_list:
            g.log_messages = True

        # Test
        for c in self.contact_list:
            self.assertTrue(c.log_messages)
        for g in self.group_list:
            self.assertTrue(g.log_messages)

        self.assertIsNone(contact_setting(UserInput('logging off all'), window, *self.args))

        for c in self.contact_list:
            self.assertFalse(c.log_messages)
        for g in self.group_list:
            self.assertFalse(g.log_messages)

    def test_enable_file_reception_for_user(self) -> None:
        # Setup
        contact                = self.contact_list.get_contact_by_address_or_nick('Alice')
        contact.file_reception = False
        window                 = TxWindow(uid=self.pub_key,
                                          type=WIN_TYPE_CONTACT,
                                          contact=contact,
                                          window_contacts=[contact])

        # Test
        self.assertFalse(contact.file_reception)
        self.assertIsNone(contact_setting(UserInput('store on'), window, *self.args))
        self.assertTrue(contact.file_reception)

    def test_enable_file_reception_for_group(self) -> None:
        # Setup
        group  = self.group_list.get_group('test_group')
        window = TxWindow(uid=group_name_to_group_id('test_group'),
                          type=WIN_TYPE_GROUP,
                          group=group,
                          window_contacts=group.members)

        for m in group:
            m.file_reception = False

        # Test
        for m in group:
            self.assertFalse(m.file_reception)
        self.assertIsNone(contact_setting(UserInput('store on'), window, *self.args))
        for m in group:
            self.assertTrue(m.file_reception)

    def test_enable_file_reception_for_all_users(self) -> None:
        # Setup
        contact = self.contact_list.get_contact_by_address_or_nick("Alice")
        window  = TxWindow(uid=self.pub_key,
                           type=WIN_TYPE_CONTACT,
                           contact=contact,
                           window_contacts=[contact])

        for c in self.contact_list:
            c.file_reception = False

        # Test
        for c in self.contact_list:
            self.assertFalse(c.file_reception)

        self.assertIsNone(contact_setting(UserInput('store on all'), window, *self.args))
        for c in self.contact_list:
            self.assertTrue(c.file_reception)

    def test_disable_file_reception_for_user(self) -> None:
        # Setup
        contact                = self.contact_list.get_contact_by_address_or_nick('Alice')
        contact.file_reception = True
        window                 = TxWindow(uid=self.pub_key,
                                          type=WIN_TYPE_CONTACT,
                                          contact=contact,
                                          window_contacts=[contact])

        # Test
        self.assertTrue(contact.file_reception)
        self.assertIsNone(contact_setting(UserInput('store off'), window, *self.args))
        self.assertFalse(contact.file_reception)

    def test_disable_file_reception_for_group(self) -> None:
        # Setup
        group  = self.group_list.get_group('test_group')
        window = TxWindow(uid=group_name_to_group_id('test_group'),
                          type=WIN_TYPE_GROUP,
                          group=group,
                          window_contacts=group.members)

        for m in group:
            m.file_reception = True

        # Test
        for m in group:
            self.assertTrue(m.file_reception)

        self.assertIsNone(contact_setting(UserInput('store off'), window, *self.args))
        for m in group:
            self.assertFalse(m.file_reception)

    def test_disable_file_reception_for_all_users(self) -> None:
        # Setup
        contact = self.contact_list.get_contact_by_address_or_nick("Alice")
        window  = TxWindow(uid=self.pub_key,
                           type=WIN_TYPE_CONTACT,
                           contact=contact,
                           window_contacts=[contact])

        for c in self.contact_list:
            c.file_reception = True

        # Test
        for c in self.contact_list:
            self.assertTrue(c.file_reception)
        self.assertIsNone(contact_setting(UserInput('store off all'), window, *self.args))
        for c in self.contact_list:
            self.assertFalse(c.file_reception)

    def test_enable_notifications_for_user(self) -> None:
        # Setup
        contact               = self.contact_list.get_contact_by_address_or_nick('Alice')
        contact.notifications = False
        window                = TxWindow(uid=self.pub_key,
                                         type=WIN_TYPE_CONTACT,
                                         contact=contact)

        # Test
        self.assertFalse(contact.notifications)
        self.assertIsNone(contact_setting(UserInput('notify on'), window, *self.args))
        self.assertTrue(contact.notifications)

    def test_enable_notifications_for_group(self) -> None:
        # Setup
        user_input          = UserInput('notify on')
        group               = self.group_list.get_group('test_group')
        group.notifications = False
        window              = TxWindow(uid=group_name_to_group_id('test_group'),
                                       type=WIN_TYPE_GROUP,
                                       group=group,
                                       window_contacts=group.members)

        # Test
        self.assertFalse(group.notifications)
        self.assertIsNone(contact_setting(user_input, window, *self.args))
        self.assertTrue(group.notifications)

    def test_enable_notifications_for_all_users(self) -> None:
        # Setup
        contact = self.contact_list.get_contact_by_address_or_nick("Alice")
        window  = TxWindow(uid=self.pub_key,
                           type=WIN_TYPE_CONTACT,
                           contact=contact,
                           window_contacts=[contact])

        for c in self.contact_list:
            c.notifications = False
        for g in self.group_list:
            g.notifications = False

        # Test
        for c in self.contact_list:
            self.assertFalse(c.notifications)
        for g in self.group_list:
            self.assertFalse(g.notifications)

        self.assertIsNone(contact_setting(UserInput('notify on all'), window, *self.args))

        for c in self.contact_list:
            self.assertTrue(c.notifications)
        for g in self.group_list:
            self.assertTrue(g.notifications)

    def test_disable_notifications_for_user(self) -> None:
        # Setup
        contact               = self.contact_list.get_contact_by_address_or_nick('Alice')
        contact.notifications = True
        window                = TxWindow(uid=self.pub_key,
                                         type=WIN_TYPE_CONTACT,
                                         contact=contact,
                                         window_contacts=[contact])

        # Test
        self.assertTrue(contact.notifications)
        self.assertIsNone(contact_setting(UserInput('notify off'), window, *self.args))
        self.assertFalse(contact.notifications)

    def test_disable_notifications_for_group(self) -> None:
        # Setup
        group               = self.group_list.get_group('test_group')
        group.notifications = True
        window              = TxWindow(uid=group_name_to_group_id('test_group'),
                                       type=WIN_TYPE_GROUP,
                                       group=group,
                                       window_contacts=group.members)

        # Test
        self.assertTrue(group.notifications)
        self.assertIsNone(contact_setting(UserInput('notify off'), window, *self.args))
        self.assertFalse(group.notifications)

    def test_disable_notifications_for_all_users(self) -> None:
        # Setup
        contact = self.contact_list.get_contact_by_address_or_nick("Alice")
        window  = TxWindow(uid=self.pub_key,
                           type=WIN_TYPE_CONTACT,
                           contact=contact,
                           window_contacts=[contact])

        for c in self.contact_list:
            c.notifications = True
        for g in self.group_list:
            g.notifications = True

        # Test
        for c in self.contact_list:
            self.assertTrue(c.notifications)
        for g in self.group_list:
            self.assertTrue(g.notifications)

        self.assertIsNone(contact_setting(UserInput('notify off all'), window, *self.args))

        for c in self.contact_list:
            self.assertFalse(c.notifications)
        for g in self.group_list:
            self.assertFalse(g.notifications)
Exemple #12
0
class TestRemoveContact(TFCTestCase):

    def setUp(self) -> None:
        """Pre-test actions."""
        self.unit_test_dir = cd_unit_test()
        self.contact_list  = ContactList(nicks=['Alice'])
        self.group_list    = GroupList(groups=['test_group'])
        self.settings      = Settings()
        self.queues        = gen_queue_dict()
        self.master_key    = MasterKey()
        self.pub_key       = nick_to_pub_key('Alice')
        self.args          = self.contact_list, self.group_list, self.settings, self.queues, self.master_key

    def tearDown(self) -> None:
        """Post-test actions."""
        cleanup(self.unit_test_dir)
        tear_queues(self.queues)

    def test_contact_removal_during_traffic_masking_raises_soft_error(self) -> None:
        # Setup
        self.settings.traffic_masking = True

        # Test
        self.assert_se("Error: Command is disabled during traffic masking.",
                       remove_contact, UserInput(), None, *self.args)

    def test_missing_account_raises_soft_error(self) -> None:
        self.assert_se("Error: No account specified.", remove_contact, UserInput('rm '), None, *self.args)

    @mock.patch('time.sleep',               return_value=None)
    @mock.patch('shutil.get_terminal_size', return_value=[150, 150])
    @mock.patch('builtins.input',           return_value='Yes')
    def test_invalid_account_raises_soft_error(self, *_: Any) -> None:
        # Setup
        user_input = UserInput(f'rm {nick_to_onion_address("Alice")[:-1]}')
        window     = TxWindow(window_contacts=[self.contact_list.get_contact_by_address_or_nick('Alice')],
                              type=WIN_TYPE_CONTACT,
                              uid=self.pub_key)

        # Test
        self.assert_se("Error: Invalid selection.", remove_contact, user_input, window, *self.args)

    @mock.patch('time.sleep',               return_value=None)
    @mock.patch('shutil.get_terminal_size', return_value=[150, 150])
    @mock.patch('builtins.input',           return_value='No')
    def test_user_abort_raises_soft_error(self, *_: Any) -> None:
        # Setup
        user_input = UserInput(f'rm {nick_to_onion_address("Alice")}')

        # Test
        self.assert_se("Removal of contact aborted.", remove_contact, user_input, None, *self.args)

    @mock.patch('builtins.input', return_value='Yes')
    def test_successful_removal_of_contact(self, _: Any) -> None:
        # Setup
        window = TxWindow(window_contacts=[self.contact_list.get_contact_by_address_or_nick('Alice')],
                          type=WIN_TYPE_CONTACT,
                          uid=self.pub_key)

        # Test
        for g in self.group_list:
            self.assertIsInstance(g, Group)
            self.assertTrue(g.has_member(self.pub_key))

        self.assertIsNone(remove_contact(UserInput('rm Alice'), window, *self.args))
        self.assertEqual(self.queues[COMMAND_PACKET_QUEUE].qsize(), 1)

        km_data = self.queues[KEY_MANAGEMENT_QUEUE].get()
        self.assertEqual(km_data, (KDB_REMOVE_ENTRY_HEADER, self.pub_key))
        self.assertFalse(self.contact_list.has_pub_key(self.pub_key))

        for g in self.group_list:
            self.assertIsInstance(g, Group)
            self.assertFalse(g.has_member(self.pub_key))

    @mock.patch('builtins.input', return_value='Yes')
    def test_successful_removal_of_last_member_of_active_group(self, _: Any) -> None:
        # Setup
        user_input    = UserInput('rm Alice')
        window        = TxWindow(window_contacts=[self.contact_list.get_contact_by_address_or_nick("Alice")],
                                 type=WIN_TYPE_GROUP,
                                 name='test_group')
        group         = self.group_list.get_group('test_group')
        group.members = [self.contact_list.get_contact_by_address_or_nick("Alice")]
        pub_key       = nick_to_pub_key('Alice')

        # Test
        for g in self.group_list:
            self.assertIsInstance(g, Group)
            self.assertTrue(g.has_member(pub_key))
        self.assertEqual(len(group), 1)

        self.assertIsNone(remove_contact(user_input, window, *self.args))

        for g in self.group_list:
            self.assertIsInstance(g, Group)
            self.assertFalse(g.has_member(pub_key))

        self.assertFalse(self.contact_list.has_pub_key(pub_key))
        self.assertEqual(self.queues[COMMAND_PACKET_QUEUE].qsize(), 1)

        km_data = self.queues[KEY_MANAGEMENT_QUEUE].get()
        self.assertEqual(km_data, (KDB_REMOVE_ENTRY_HEADER, pub_key))

    @mock.patch('shutil.get_terminal_size', return_value=[150, 150])
    @mock.patch('builtins.input',           return_value='Yes')
    def test_no_contact_found_on_transmitter(self, *_: Any) -> None:
        # Setup
        user_input   = UserInput(f'rm {nick_to_onion_address("Charlie")}')
        contact_list = ContactList(nicks=['Bob'])
        window       = TxWindow(window_contact=[contact_list.get_contact_by_address_or_nick('Bob')],
                                type=WIN_TYPE_GROUP)

        # Test
        self.assertIsNone(remove_contact(user_input, window, *self.args))
        self.assertEqual(self.queues[COMMAND_PACKET_QUEUE].qsize(), 1)
        self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(),   1)
        command_packet = self.queues[COMMAND_PACKET_QUEUE].get()
        self.assertIsInstance(command_packet, bytes)
Exemple #13
0
class TestKeyExchange(TFCTestCase):
    def setUp(self):
        self.contact_list = ContactList()
        self.settings = Settings()
        self.queues = gen_queue_dict()
        self.args = self.contact_list, self.settings, self.queues

    def tearDown(self):
        tear_queues(self.queues)

    @mock.patch('shutil.get_terminal_size', return_value=[200, 200])
    @mock.patch('builtins.input',
                return_value=b58encode(bytes(TFC_PUBLIC_KEY_LENGTH),
                                       public_key=True))
    def test_zero_public_key_raises_fr(self, *_):
        self.assert_fr("Error: Zero public key", start_key_exchange,
                       nick_to_pub_key("Alice"), 'Alice', *self.args)

    @mock.patch('shutil.get_terminal_size', return_value=[200, 200])
    @mock.patch('builtins.input',
                return_value=b58encode((TFC_PUBLIC_KEY_LENGTH - 1) * b'a',
                                       public_key=True))
    def test_invalid_public_key_length_raises_fr(self, *_):
        self.assert_fr("Error: Invalid public key length", start_key_exchange,
                       nick_to_pub_key("Alice"), 'Alice', *self.args)

    @mock.patch(
        'builtins.input',
        side_effect=[
            '',  # Empty message should resend key
            VALID_ECDHE_PUB_KEY[:-1],  # Short key should fail
            VALID_ECDHE_PUB_KEY + 'a',  # Long key should fail
            VALID_ECDHE_PUB_KEY[:-1] + 'a',  # Invalid key should fail
            VALID_ECDHE_PUB_KEY,  # Correct key
            'No'
        ])  # Fingerprint mismatch)
    @mock.patch('time.sleep', return_value=None)
    @mock.patch('shutil.get_terminal_size', return_value=[200, 200])
    def test_fingerprint_mismatch_raises_fr(self, *_):
        self.assert_fr("Error: Fingerprint mismatch", start_key_exchange,
                       nick_to_pub_key("Alice"), 'Alice', *self.args)

    @mock.patch(
        'builtins.input',
        side_effect=[
            '',  # Resend public key
            VALID_ECDHE_PUB_KEY,  # Correct key
            'Yes',  # Fingerprint match
            '',  # Resend contact data
            'ff',  # Invalid confirmation code
            blake2b(nick_to_pub_key('Alice'),
                    digest_size=CONFIRM_CODE_LENGTH).hex()
        ])
    @mock.patch('shutil.get_terminal_size', return_value=[200, 200])
    @mock.patch('time.sleep', return_value=None)
    def test_successful_exchange(self, *_):
        self.assertIsNone(
            start_key_exchange(nick_to_pub_key("Alice"), 'Alice', *self.args))

        contact = self.contact_list.get_contact_by_pub_key(
            nick_to_pub_key("Alice"))
        self.assertEqual(contact.onion_pub_key, nick_to_pub_key("Alice"))
        self.assertEqual(contact.nick, 'Alice')
        self.assertEqual(contact.kex_status, KEX_STATUS_VERIFIED)
        self.assertIsInstance(contact.tx_fingerprint, bytes)
        self.assertIsInstance(contact.rx_fingerprint, bytes)
        self.assertEqual(len(contact.tx_fingerprint), FINGERPRINT_LENGTH)
        self.assertEqual(len(contact.rx_fingerprint), FINGERPRINT_LENGTH)
        self.assertFalse(contact.log_messages)
        self.assertFalse(contact.file_reception)
        self.assertTrue(contact.notifications)

        self.assertEqual(self.queues[COMMAND_PACKET_QUEUE].qsize(), 2)
        self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(), 2)

        cmd, account, tx_key, rx_key, tx_hek, rx_hek = self.queues[
            KEY_MANAGEMENT_QUEUE].get()

        self.assertEqual(cmd, KDB_ADD_ENTRY_HEADER)
        self.assertEqual(account, nick_to_pub_key("Alice"))
        self.assertEqual(len(tx_key), SYMMETRIC_KEY_LENGTH)

        for key in [tx_key, rx_key, tx_hek, rx_hek]:
            self.assertIsInstance(key, bytes)
            self.assertEqual(len(key), SYMMETRIC_KEY_LENGTH)

    @mock.patch(
        'builtins.input',
        side_effect=[
            '',  # Resend public key
            VALID_ECDHE_PUB_KEY,  # Correct key
            KeyboardInterrupt,  # Skip fingerprint verification
            '',  # Manual proceed for warning message
            blake2b(nick_to_pub_key('Alice'),
                    digest_size=CONFIRM_CODE_LENGTH).hex()
        ])
    @mock.patch('time.sleep', return_value=None)
    @mock.patch('shutil.get_terminal_size', return_value=[200, 200])
    def test_successful_exchange_skip_fingerprint_verification(self, *_):
        self.assertIsNone(
            start_key_exchange(nick_to_pub_key("Alice"), 'Alice', *self.args))

        contact = self.contact_list.get_contact_by_pub_key(
            nick_to_pub_key("Alice"))
        self.assertEqual(contact.onion_pub_key, nick_to_pub_key("Alice"))
        self.assertEqual(contact.nick, 'Alice')
        self.assertEqual(contact.kex_status, KEX_STATUS_UNVERIFIED)

    @mock.patch(
        'os.getrandom',
        side_effect=[SYMMETRIC_KEY_LENGTH * b'a', SYMMETRIC_KEY_LENGTH * b'a'])
    @mock.patch('builtins.input',
                side_effect=[
                    KeyboardInterrupt, VALID_ECDHE_PUB_KEY, 'Yes',
                    blake2b(nick_to_pub_key('Alice'),
                            digest_size=CONFIRM_CODE_LENGTH).hex()
                ])
    @mock.patch('time.sleep', return_value=None)
    @mock.patch('shutil.get_terminal_size', return_value=[200, 200])
    def test_successful_exchange_with_previous_key(self, *_):
        # Test caching of private key
        self.assert_fr("Key exchange interrupted.", start_key_exchange,
                       nick_to_pub_key('Alice'), 'Alice', *self.args)

        alice = self.contact_list.get_contact_by_address_or_nick('Alice')
        self.assertEqual(alice.kex_status, KEX_STATUS_PENDING)

        # Test re-using private key
        self.assertIsNone(
            start_key_exchange(nick_to_pub_key('Alice'), 'Alice', *self.args))
        self.assertIsNone(alice.tfc_private_key)
        self.assertEqual(alice.kex_status, KEX_STATUS_VERIFIED)
Exemple #14
0
class TestTxWindow(TFCTestCase):
    def setUp(self):
        self.contact_list = ContactList(['Alice', 'Bob'])
        self.group_list = GroupList(groups=['test_group', 'test_group_2'])
        self.window = TxWindow(self.contact_list, self.group_list)
        self.window.group = self.group_list.get_group('test_group')
        self.window.type = WIN_TYPE_GROUP
        self.settings = Settings()
        self.queues = gen_queue_dict()
        self.onion_service = OnionService()
        self.gateway = Gateway()
        self.args = self.settings, self.queues, self.onion_service, self.gateway

    def tearDown(self):
        tear_queues(self.queues)

    def test_window_iterates_over_contacts(self):
        # Setup
        self.window.window_contacts = self.contact_list.contacts

        # Test
        for c in self.window:
            self.assertIsInstance(c, Contact)

    def test_len_returns_number_of_contacts_in_window(self):
        # Setup
        self.window.window_contacts = self.contact_list.contacts

        # Test
        self.assertEqual(len(self.window), 2)

    def test_group_window_change_during_traffic_masking_raises_fr(self):
        # Setup
        self.settings.traffic_masking = True
        self.window.uid = 'test_group'

        # Test
        self.assert_fr("Error: Can't change window during traffic masking.",
                       self.window.select_tx_window,
                       *self.args,
                       selection='test_group_2',
                       cmd=True)

    def test_contact_window_change_during_traffic_masking_raises_fr(self):
        # Setup
        self.settings.traffic_masking = True
        self.window.uid = nick_to_pub_key("Alice")

        # Test
        self.assert_fr("Error: Can't change window during traffic masking.",
                       self.window.select_tx_window,
                       *self.args,
                       selection=nick_to_onion_address("Bob"),
                       cmd=True)

    def test_contact_window_reload_during_traffic_masking(self):
        # Setup
        self.settings.traffic_masking = True
        self.window.uid = nick_to_pub_key("Alice")

        # Test
        self.assertIsNone(
            self.window.select_tx_window(
                *self.args, selection=nick_to_onion_address("Alice"),
                cmd=True))
        self.assertEqual(self.window.uid, nick_to_pub_key("Alice"))

    def test_group_window_reload_during_traffic_masking(self):
        # Setup
        self.settings.traffic_masking = True
        self.window.name = 'test_group'
        self.window.uid = group_name_to_group_id('test_group')

        # Test
        self.assertIsNone(
            self.window.select_tx_window(*self.args,
                                         selection='test_group',
                                         cmd=True))
        self.assertEqual(self.window.uid, group_name_to_group_id('test_group'))

    def test_invalid_selection_raises_fr(self):
        # Setup
        self.window.uid = nick_to_pub_key("Alice")

        # Test
        self.assert_fr("Error: No contact/group was found.",
                       self.window.select_tx_window,
                       *self.args,
                       selection=nick_to_onion_address("Charlie"),
                       cmd=True)

    @mock.patch('builtins.input', return_value=nick_to_onion_address("Bob"))
    def test_window_selection_during_traffic_masking(self, *_):
        # Setup
        self.settings.traffic_masking = True
        self.window.uid = None

        # Test
        self.assertIsNone(self.window.select_tx_window(*self.args))
        self.assertEqual(self.queues[WINDOW_SELECT_QUEUE].qsize(), 1)

    @mock.patch('builtins.input', return_value=nick_to_onion_address("Bob"))
    def test_contact_window_selection_from_input(self, *_):
        # Setup
        self.window.uid = None

        # Test
        self.assertIsNone(self.window.select_tx_window(*self.args))
        self.assertEqual(self.window.uid, nick_to_pub_key("Bob"))

    def test_group_window_selection_from_command(self):
        # Setup
        self.window.uid = None

        self.assertIsNone(
            self.window.select_tx_window(*self.args,
                                         selection='test_group',
                                         cmd=True))
        self.assertEqual(self.window.uid, group_name_to_group_id('test_group'))

    def test_deselect_window(self):
        # Setup
        self.window.window_contacts = self.contact_list.contacts
        self.window.contact = self.contact_list.get_contact_by_address_or_nick(
            "Bob")
        self.window.name = 'Bob'
        self.window.type = WIN_TYPE_CONTACT
        self.window.uid = nick_to_pub_key("Bob")

        # Test
        self.assertIsNone(self.window.deselect())
        self.assertIsNone(self.window.contact)
        self.assertEqual(self.window.name, '')
        self.assertEqual(self.window.type, '')
        self.assertEqual(self.window.uid, b'')

    def test_is_selected(self):
        self.window.name = ''
        self.assertFalse(self.window.is_selected())

        self.window.name = nick_to_pub_key("Bob")
        self.assertTrue(self.window.is_selected())

    def test_update_log_messages_for_contact(self):
        # Setup
        self.window.type = WIN_TYPE_CONTACT
        self.window.log_messages = None
        self.window.contact = self.contact_list.get_contact_by_address_or_nick(
            'Alice')
        self.window.contact.log_messages = False

        # Test
        self.assertIsNone(self.window.update_log_messages())
        self.assertFalse(self.window.log_messages)

    def test_update_log_messages_for_group(self):
        # Setup
        self.window.type = WIN_TYPE_GROUP
        self.window.log_messages = None
        self.window.group = self.group_list.get_group('test_group')
        self.window.group.log_messages = False

        # Test
        self.assertIsNone(self.window.update_log_messages())
        self.assertFalse(self.window.log_messages)

    def test_update_group_win_members_if_group_is_available(self):
        # Setup
        self.window.window_contacts = []
        self.window.group = None
        self.window.group_id = group_name_to_group_id('test_group')
        self.window.name = 'test_group'
        self.window.type = WIN_TYPE_GROUP

        # Test
        self.assertIsNone(self.window.update_window(self.group_list))
        self.assertEqual(self.window.group,
                         self.group_list.get_group('test_group'))
        self.assertEqual(self.window.window_contacts,
                         self.window.group.members)

    def test_window_contact_is_reloaded_when_contact_is_active(self):
        # Setup
        self.window.type = WIN_TYPE_CONTACT
        self.window.contact = create_contact('Alice')
        self.window.window_contacts = [self.window.contact]
        self.assertIsNot(
            self.window.contact,
            self.window.contact_list.get_contact_by_pub_key(
                nick_to_pub_key('Alice')))
        self.assertIsNot(
            self.window.window_contacts[0],
            self.window.contact_list.get_contact_by_pub_key(
                nick_to_pub_key('Alice')))

        # Test
        self.assertIsNone(self.window.update_window(self.group_list))
        self.assertIs(
            self.window.contact,
            self.window.contact_list.get_contact_by_pub_key(
                nick_to_pub_key('Alice')))
        self.assertIs(
            self.window.window_contacts[0],
            self.window.contact_list.get_contact_by_pub_key(
                nick_to_pub_key('Alice')))

    def test_deactivate_window_if_group_is_not_available(self):
        # Setup
        self.window.window_contacts = []
        self.window.group = None
        self.window.name = 'test_group_3'
        self.window.type = WIN_TYPE_GROUP

        # Test
        self.assertIsNone(self.window.update_window(self.group_list))
        self.assertIsNone(self.window.contact)
        self.assertEqual(self.window.name, '')
        self.assertEqual(self.window.type, '')
        self.assertEqual(self.window.uid, b'')

    @mock.patch('time.sleep', return_value=None)
    @mock.patch('builtins.input',
                side_effect=[
                    'Alice', VALID_ECDHE_PUB_KEY, 'yes',
                    blake2b(nick_to_pub_key('Alice'),
                            digest_size=CONFIRM_CODE_LENGTH).hex()
                ])
    @mock.patch('shutil.get_terminal_size', return_value=[200, 200])
    def test_selecting_pending_contact_starts_key_exchange(self, *_):
        # Setup
        alice = self.contact_list.get_contact_by_address_or_nick('Alice')
        bob = self.contact_list.get_contact_by_address_or_nick('Bob')
        alice.kex_status = KEX_STATUS_PENDING
        bob.kex_status = KEX_STATUS_PENDING

        # Test
        self.assertIsNone(self.window.select_tx_window(*self.args))
        self.assertEqual(self.queues[COMMAND_PACKET_QUEUE].qsize(), 2)
        self.assertEqual(self.queues[WINDOW_SELECT_QUEUE].qsize(), 0)
        self.assertEqual(alice.kex_status, KEX_STATUS_VERIFIED)

    @mock.patch('time.sleep', return_value=None)
    @mock.patch('builtins.input',
                side_effect=[
                    '/add',
                    nick_to_onion_address('Alice'), 'Alice', '',
                    VALID_ECDHE_PUB_KEY, 'yes',
                    blake2b(nick_to_pub_key('Alice'),
                            digest_size=CONFIRM_CODE_LENGTH).hex()
                ])
    @mock.patch('shutil.get_terminal_size', return_value=[200, 200])
    def test_adding_new_contact_from_contact_selection(self, *_):
        # Setup
        alice = self.contact_list.get_contact_by_address_or_nick('Alice')
        alice.kex_status = KEX_STATUS_PENDING

        # Test
        self.assert_fr('New contact added.', self.window.select_tx_window,
                       *self.args)
        self.assertEqual(self.queues[COMMAND_PACKET_QUEUE].qsize(), 1)
        self.assertEqual(self.queues[WINDOW_SELECT_QUEUE].qsize(), 0)
        self.assertEqual(alice.kex_status, KEX_STATUS_VERIFIED)

    @mock.patch('time.sleep', return_value=None)
    @mock.patch('builtins.input', side_effect=['/rm '])
    def test_missing_account_when_removing_raises_fr(self, *_):
        self.assert_fr("Error: No account specified.",
                       self.window.select_tx_window, *self.args)

    @mock.patch('time.sleep', return_value=None)
    @mock.patch('builtins.input', side_effect=['/rm Charlie', 'yes'])
    def test_unknown_account_when_removing_raises_fr(self, *_):
        self.assert_fr("Error: Unknown contact 'Charlie'.",
                       self.window.select_tx_window, *self.args)

    @mock.patch('time.sleep', return_value=None)
    @mock.patch('builtins.input', side_effect=['/rm Alice', 'no'])
    def test_abort_removal_of_contact_form_contact_selection(self, *_):
        self.assert_fr("Removal of contact aborted.",
                       self.window.select_tx_window, *self.args)

    @mock.patch('time.sleep', return_value=None)
    @mock.patch('builtins.input', side_effect=['/rm Alice', 'yes'])
    def test_removing_pending_contact_from_contact_selection(self, *_):
        self.assert_fr("Removed contact 'Alice'.",
                       self.window.select_tx_window, *self.args)

    @mock.patch('time.sleep', return_value=None)
    @mock.patch('builtins.input', side_effect=['/connect', b'a'.hex()])
    def test_sending_onion_service_data_from_contact_selection(self, *_):
        self.assertIsNone(self.window.select_tx_window(*self.args))
        self.assertEqual(len(self.gateway.packets), 1)

    @mock.patch('time.sleep', return_value=None)
    @mock.patch('builtins.input', side_effect=['/help'])
    def test_invalid_command_raises_fr(self, *_):
        self.assert_fr("Error: Invalid command.", self.window.select_tx_window,
                       *self.args)
Exemple #15
0
class TestRxWindow(TFCTestCase):
    def setUp(self):
        """Pre-test actions."""
        self.contact_list = ContactList(
            nicks=['Alice', 'Bob', 'Charlie', LOCAL_ID])
        self.group_list = GroupList(groups=['test_group', 'test_group2'])
        self.settings = Settings()
        self.packet_list = PacketList()
        self.ts = datetime.fromtimestamp(1502750000)
        self.time = self.ts.strftime('%H:%M:%S.%f')[:-4]

        group = self.group_list.get_group('test_group')
        group.members = list(
            map(self.contact_list.get_contact_by_address_or_nick,
                ['Alice', 'Bob', 'Charlie']))

    def create_window(self, uid: bytes):
        """Create new RxWindow object."""
        return RxWindow(uid, self.contact_list, self.group_list, self.settings,
                        self.packet_list)

    def test_command_window_creation(self):
        window = self.create_window(WIN_UID_LOCAL)
        self.assertEqual(window.type, WIN_TYPE_COMMAND)
        self.assertEqual(window.name, WIN_TYPE_COMMAND)

    def test_file_window_creation(self):
        window = self.create_window(WIN_UID_FILE)
        self.assertEqual(window.type, WIN_TYPE_FILE)

    def test_contact_window_creation(self):
        window = self.create_window(nick_to_pub_key("Alice"))
        self.assertEqual(window.type, WIN_TYPE_CONTACT)
        self.assertEqual(window.window_contacts[0].onion_pub_key,
                         nick_to_pub_key("Alice"))
        self.assertEqual(window.name, 'Alice')

    def test_group_window_creation(self):
        window = self.create_window(group_name_to_group_id('test_group'))
        self.assertEqual(window.type, WIN_TYPE_GROUP)
        self.assertEqual(window.window_contacts[0].onion_pub_key,
                         nick_to_pub_key("Alice"))
        self.assertEqual(window.name, 'test_group')

    def test_invalid_uid_raises_fr(self):
        self.assert_fr(
            "Invalid window 'mfqwcylbmfqwcylbmfqwcylbmfqwcylbmfqwcylbmfqwcylbmfqwbfad'.",
            self.create_window, ONION_SERVICE_PUBLIC_KEY_LENGTH * b'a')

        self.assert_fr("Invalid window '2dnAMoWNfTXAJ'.", self.create_window,
                       GROUP_ID_LENGTH * b'a')

        self.assert_fr("Invalid window '<unable to encode>'.",
                       self.create_window, b'bad_uid')

    def test_window_iterates_over_message_tuples(self):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))
        window.message_log = 5 * [
            (datetime.now(), 'Lorem ipsum', nick_to_pub_key("Alice"),
             ORIGIN_CONTACT_HEADER, False, False)
        ]

        # Test
        for mt in window:
            self.assertEqual(mt[1:], ("Lorem ipsum", nick_to_pub_key("Alice"),
                                      ORIGIN_CONTACT_HEADER, False, False))

    def test_len_returns_number_of_messages_in_window(self):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))
        window.message_log = 5 * [
            (datetime.now(), "Lorem ipsum", nick_to_pub_key("Alice"),
             ORIGIN_CONTACT_HEADER, False, False)
        ]

        # Test
        self.assertEqual(len(window), 5)

    def test_remove_contacts(self):
        # Setup
        window = self.create_window(group_name_to_group_id('test_group'))

        # Test
        self.assertEqual(len(window.window_contacts), 3)
        self.assertIsNone(
            window.remove_contacts([
                nick_to_pub_key("Alice"),
                nick_to_pub_key("Bob"),
                nick_to_pub_key("DoesNotExist")
            ]))
        self.assertEqual(len(window.window_contacts), 1)

    def test_add_contacts(self):
        # Setup
        window = self.create_window(group_name_to_group_id('test_group'))
        window.window_contacts = [
            self.contact_list.get_contact_by_address_or_nick('Alice')
        ]

        # Test
        self.assertIsNone(
            window.add_contacts([
                nick_to_pub_key("Alice"),
                nick_to_pub_key("Bob"),
                nick_to_pub_key("DoesNotExist")
            ]))
        self.assertEqual(len(window.window_contacts), 2)

    def test_reset_window(self):
        # Setup
        window = self.create_window(group_name_to_group_id('test_group'))
        window.message_log = \
            [(datetime.now(), "Hi everybody", nick_to_pub_key("Alice"), ORIGIN_USER_HEADER,    False, False),
             (datetime.now(), "Hi David",     nick_to_pub_key("Alice"), ORIGIN_CONTACT_HEADER, False, False),
             (datetime.now(), "Hi David",     nick_to_pub_key("Bob"),   ORIGIN_CONTACT_HEADER, False, False)]

        # Test
        self.assertIsNone(window.reset_window())
        self.assertEqual(len(window), 0)

    def test_has_contact(self):
        window = self.create_window(group_name_to_group_id('test_group'))
        self.assertTrue(window.has_contact(nick_to_pub_key("Alice")))
        self.assertFalse(window.has_contact(nick_to_pub_key("DoesNotExist")))

    def test_create_handle_dict(self):
        # Setup
        window = self.create_window(group_name_to_group_id('test_group'))
        message_log = [
            (datetime.now(), "Lorem ipsum", nick_to_pub_key("Alice"),
             ORIGIN_CONTACT_HEADER, False, False),
            (datetime.now(), "Lorem ipsum", nick_to_pub_key("Bob"),
             ORIGIN_USER_HEADER, False, False),
            (datetime.now(), "Lorem ipsum", nick_to_pub_key("Charlie"),
             ORIGIN_CONTACT_HEADER, False, False),
            (datetime.now(), "Lorem ipsum", nick_to_pub_key("Charlie"),
             ORIGIN_CONTACT_HEADER, True, False),
            (datetime.now(), "Lorem ipsum", nick_to_pub_key("Charlie"),
             ORIGIN_CONTACT_HEADER, False, False),
            (datetime.now(), "Lorem ipsum", nick_to_pub_key("David"),
             ORIGIN_CONTACT_HEADER, False, False),
            (datetime.now(), "Lorem ipsum", nick_to_pub_key("Eric"),
             ORIGIN_CONTACT_HEADER, False, False)
        ]

        # Test
        self.assertIsNone(window.create_handle_dict(message_log))
        self.assertEqual(
            window.handle_dict, {
                nick_to_pub_key("Alice"): 'Alice',
                nick_to_pub_key("Bob"): 'Bob',
                nick_to_pub_key("Charlie"): 'Charlie',
                nick_to_pub_key("David"): nick_to_short_address("David"),
                nick_to_pub_key("Eric"): nick_to_short_address("Eric")
            })

    def test_get_command_handle(self):
        # Setup
        window = self.create_window(WIN_UID_LOCAL)
        window.is_active = True

        # Test
        self.assertEqual(
            window.get_handle(self.ts, WIN_UID_LOCAL, ORIGIN_USER_HEADER),
            f"{self.time} -!- ")

    def test_get_contact_handle(self):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))
        window.is_active = True
        window.handle_dict = {nick_to_pub_key("Alice"): 'Alice'}

        # Test
        self.assertEqual(
            window.get_handle(self.ts, nick_to_pub_key("Alice"),
                              ORIGIN_USER_HEADER), f"{self.time}    Me: ")
        self.assertEqual(
            window.get_handle(self.ts, nick_to_pub_key("Alice"),
                              ORIGIN_CONTACT_HEADER), f"{self.time} Alice: ")

        window.is_active = False
        self.assertEqual(
            window.get_handle(self.ts, nick_to_pub_key("Alice"),
                              ORIGIN_USER_HEADER),
            f"{self.time} Me (private message): ")
        self.assertEqual(
            window.get_handle(self.ts, nick_to_pub_key("Alice"),
                              ORIGIN_CONTACT_HEADER),
            f"{self.time} Alice (private message): ")

    def test_get_group_contact_handle(self):
        # Setup
        window = self.create_window(group_name_to_group_id('test_group'))
        window.is_active = True
        window.handle_dict = {
            nick_to_pub_key("Alice"): 'Alice',
            nick_to_pub_key("Charlie"): 'Charlie',
            nick_to_pub_key("David"): nick_to_short_address("David"),
            nick_to_pub_key("Eric"): nick_to_short_address("Eric")
        }

        # Test
        self.assertEqual(
            window.get_handle(self.ts, nick_to_pub_key("Alice"),
                              ORIGIN_USER_HEADER), f"{self.time}      Me: ")
        self.assertEqual(
            window.get_handle(self.ts, nick_to_pub_key("Charlie"),
                              ORIGIN_CONTACT_HEADER), f"{self.time} Charlie: ")

        window.is_active = False
        self.assertEqual(
            window.get_handle(self.ts, nick_to_pub_key("Alice"),
                              ORIGIN_USER_HEADER),
            f"{self.time} Me (group test_group): ")
        self.assertEqual(
            window.get_handle(self.ts, nick_to_pub_key("Charlie"),
                              ORIGIN_CONTACT_HEADER),
            f"{self.time} Charlie (group test_group): ")

    @mock.patch('time.sleep', return_value=None)
    def test_print_to_inactive_window_preview_on_short_message(self, _):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))
        window.handle_dict = {nick_to_pub_key("Alice"): 'Alice'}
        window.is_active = False
        window.settings = Settings(new_message_notify_preview=True)
        msg_tuple = (self.ts, "Hi Bob", nick_to_pub_key("Bob"),
                     ORIGIN_USER_HEADER, False, False)

        # Test
        self.assert_prints(
            f"{BOLD_ON}{self.time} Me (private message): {NORMAL_TEXT}"
            f"Hi Bob\n{CURSOR_UP_ONE_LINE}{CLEAR_ENTIRE_LINE}", window.print,
            msg_tuple)

    @mock.patch('time.sleep', return_value=None)
    def test_print_to_inactive_window_preview_on_long_message(self, _):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))
        window.is_active = False
        window.handle_dict = {nick_to_pub_key("Alice"): 'Alice'}
        window.settings = Settings(new_message_notify_preview=True)
        long_message = (
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque consequat libero et lao"
            "reet egestas. Aliquam a arcu malesuada, elementum metus eget, elementum mi. Vestibulum i"
            "d arcu sem. Ut sodales odio sed viverra mollis. Praesent gravida ante tellus, pellentesq"
            "ue venenatis massa placerat quis. Nullam in magna porta, hendrerit sem vel, dictum ipsum"
            ". Ut sagittis, ipsum ut bibendum ornare, ex lorem congue metus, vel posuere metus nulla "
            "at augue.")
        msg_tuple = (self.ts, long_message, nick_to_pub_key("Bob"),
                     ORIGIN_USER_HEADER, False, False)

        # Test
        self.assert_prints(
            f"{BOLD_ON}{self.time} Me (private message): {NORMAL_TEXT}Lorem ipsum dolor sit "
            f"amet, consectetu…\n{CURSOR_UP_ONE_LINE}{CLEAR_ENTIRE_LINE}",
            window.print, msg_tuple)

    @mock.patch('time.sleep', return_value=None)
    def test_print_to_inactive_window_preview_off(self, _):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))
        window.is_active = False
        window.handle_dict = {nick_to_pub_key("Alice"): 'Alice'}
        window.settings = Settings(new_message_notify_preview=False)
        msg_tuple = (self.ts, "Hi Bob", nick_to_pub_key("Bob"),
                     ORIGIN_USER_HEADER, False, False)

        # Test
        self.assert_prints(
            f"{BOLD_ON}{self.time} Me (private message): {NORMAL_TEXT}{BOLD_ON}1 unread message{NORMAL_TEXT}\n"
            f"{CURSOR_UP_ONE_LINE}{CLEAR_ENTIRE_LINE}", window.print,
            msg_tuple)

    def test_print_to_active_window_no_date_change(self):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))
        window.previous_msg_ts = datetime.fromtimestamp(1502750000)
        window.is_active = True
        window.handle_dict = {nick_to_pub_key("Bob"): 'Bob'}
        window.settings = Settings(new_message_notify_preview=False)
        msg_tuple = (self.ts, "Hi Alice", nick_to_pub_key("Bob"),
                     ORIGIN_CONTACT_HEADER, False, False)

        # Test
        self.assert_prints(
            f"{BOLD_ON}{self.time} Bob: {NORMAL_TEXT}Hi Alice\n", window.print,
            msg_tuple)

    def test_print_to_active_window_with_date_change_and_whisper(self):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))
        window.previous_msg_ts = datetime.fromtimestamp(1501750000)
        window.is_active = True
        window.handle_dict = {nick_to_pub_key("Bob"): 'Bob'}
        window.settings = Settings(new_message_notify_preview=False)
        msg_tuple = (self.ts, "Hi Alice", nick_to_pub_key("Bob"),
                     ORIGIN_CONTACT_HEADER, True, False)
        self.time = self.ts.strftime('%H:%M:%S.%f')[:-4]

        # Test
        self.assert_prints(
            f"""\
{BOLD_ON}00:00 -!- Day changed to 2017-08-15{NORMAL_TEXT}
{BOLD_ON}{self.time} Bob (whisper): {NORMAL_TEXT}Hi Alice
""", window.print, msg_tuple)

    def test_print_to_active_window_with_date_change_and_whisper_empty_message(
            self):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))
        window.previous_msg_ts = datetime.fromtimestamp(1501750000)
        window.is_active = True
        window.handle_dict = {nick_to_pub_key("Bob"): 'Bob'}
        window.settings = Settings(new_message_notify_preview=False)
        msg_tuple = (self.ts, " ", nick_to_pub_key("Bob"),
                     ORIGIN_CONTACT_HEADER, True, False)

        # Test
        self.assert_prints(
            f"""\
{BOLD_ON}00:00 -!- Day changed to 2017-08-15{NORMAL_TEXT}
{BOLD_ON}{self.time} Bob (whisper): {NORMAL_TEXT}
""", window.print, msg_tuple)

    @mock.patch('time.sleep', return_value=None)
    def test_print_new(self, _):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))

        # Test
        self.assertIsNone(
            window.add_new(self.ts,
                           "Hi Alice",
                           nick_to_pub_key("Bob"),
                           ORIGIN_CONTACT_HEADER,
                           output=True))
        self.assertEqual(len(window.message_log), 1)
        self.assertEqual(window.handle_dict[nick_to_pub_key("Bob")], 'Bob')

    def test_redraw_message_window(self):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))
        window.is_active = True
        window.message_log = [(self.ts, "Hi Alice", nick_to_pub_key("Bob"),
                               ORIGIN_CONTACT_HEADER, False, False)]
        window.unread_messages = 1

        # Test
        self.assert_prints(
            f"""\
{CLEAR_ENTIRE_SCREEN}{CURSOR_LEFT_UP_CORNER}
------------------------------- Unread Messages --------------------------------

{BOLD_ON}{self.time}   Bob: {NORMAL_TEXT}Hi Alice
""", window.redraw)
        self.assertEqual(window.unread_messages, 0)

    def test_redraw_empty_window(self):
        # Setup
        window = self.create_window(nick_to_pub_key("Alice"))
        window.is_active = True
        window.message_log = []

        # Test
        self.assert_prints(
            f"""\
{CLEAR_ENTIRE_SCREEN}{CURSOR_LEFT_UP_CORNER}
{BOLD_ON}                   This window for Alice is currently empty.                    {NORMAL_TEXT}\n
""", window.redraw)

    @mock.patch('time.sleep', return_value=None)
    def test_redraw_file_win(self, _):
        # Setup
        self.packet_list.packets = [
            Packet(type=FILE,
                   name='testfile.txt',
                   assembly_pt_list=5 * [b'a'],
                   packets=10,
                   size="100.0KB",
                   contact=create_contact('Bob')),
            Packet(type=FILE,
                   name='testfile2.txt',
                   assembly_pt_list=7 * [b'a'],
                   packets=100,
                   size="15.0KB",
                   contact=create_contact('Charlie'))
        ]

        # Test
        window = self.create_window(WIN_UID_FILE)
        self.assert_prints(
            f"""\

File name        Size       Sender     Complete    
────────────────────────────────────────────────────────────────────────────────
testfile.txt     100.0KB    Bob        50.00%      
testfile2.txt    15.0KB     Charlie    7.00%       

{6*(CURSOR_UP_ONE_LINE+CLEAR_ENTIRE_LINE)}""", window.redraw_file_win)

    @mock.patch('time.sleep', return_value=None)
    def test_redraw_empty_file_win(self, _):
        # Setup
        self.packet_list.packet_l = []

        # Test
        window = self.create_window(WIN_UID_FILE)
        self.assert_prints(
            f"""\

{BOLD_ON}                  No file transmissions currently in progress.                  {NORMAL_TEXT}

{3*(CURSOR_UP_ONE_LINE+CLEAR_ENTIRE_LINE)}""", window.redraw_file_win)
Exemple #16
0
    def test_loop(self):
        # Setup
        queues                 = gen_queue_dict()
        settings               = Settings(traffic_masking=False)
        gateway                = Gateway()
        key_list               = KeyList()
        window                 = TxWindow(log_messages=True)
        contact_list           = ContactList(nicks=['Alice', LOCAL_ID])
        window.contact_list    = contact_list
        window.window_contacts = [contact_list.get_contact_by_address_or_nick('Alice')]
        user_input             = UserInput(plaintext='test')

        delay = 0.01

        def queue_delayer():
            """Place datagrams into queue after delay."""
            time.sleep(delay)
            queue_command(b'test', settings, queues)

            time.sleep(delay)
            queue_to_nc(PUBLIC_KEY_DATAGRAM_HEADER + TFC_PUBLIC_KEY_LENGTH * b'a' + nick_to_pub_key('Alice'),  # 1
                        queues[RELAY_PACKET_QUEUE])

            time.sleep(delay)
            queue_to_nc(UNENCRYPTED_DATAGRAM_HEADER + UNENCRYPTED_WIPE_COMMAND, queues[RELAY_PACKET_QUEUE])  # 2

            time.sleep(delay)
            queue_to_nc(UNENCRYPTED_DATAGRAM_HEADER + UNENCRYPTED_EXIT_COMMAND, queues[RELAY_PACKET_QUEUE])  # 3

            time.sleep(delay)
            queues[KEY_MANAGEMENT_QUEUE].put((KDB_ADD_ENTRY_HEADER, LOCAL_PUBKEY,  # 4
                                              SYMMETRIC_KEY_LENGTH * b'a', SYMMETRIC_KEY_LENGTH * b'a',
                                              SYMMETRIC_KEY_LENGTH * b'a', SYMMETRIC_KEY_LENGTH * b'a'))

            time.sleep(delay)
            queue_message(user_input, window, settings, queues)  # 5

            time.sleep(delay)
            queue_message(user_input, window, settings, queues)  # 6

            time.sleep(delay)
            queues[KEY_MANAGEMENT_QUEUE].put((KDB_ADD_ENTRY_HEADER, nick_to_pub_key('Alice'),
                                              SYMMETRIC_KEY_LENGTH * b'a', SYMMETRIC_KEY_LENGTH * b'a',
                                              SYMMETRIC_KEY_LENGTH * b'a', SYMMETRIC_KEY_LENGTH * b'a'))

            time.sleep(delay)
            queue_message(user_input, window, settings, queues)  # 7

            time.sleep(delay)
            queue_message(user_input, window, settings, queues)  # 8

            time.sleep(delay)
            queues[SENDER_MODE_QUEUE].put(settings)

        threading.Thread(target=queue_delayer).start()

        # Test
        settings, m_buffer = standard_sender_loop(queues, gateway, key_list)
        self.assertIsInstance(settings, Settings)
        self.assertEqual(m_buffer,                   {nick_to_pub_key('Alice'): []})
        self.assertEqual(len(gateway.packets),       8)
        self.assertEqual(queues[EXIT_QUEUE].qsize(), 2)

        # Teardown
        tear_queues(queues)