Exemplo n.º 1
0
 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
Exemplo n.º 2
0
 def setUp(self):
     self.contact_list = ContactList(nicks=['Alice'])
     self.group_list = GroupList()
     self.user_input = UserInput()
     self.window = TxWindow(self.contact_list, self.group_list)
     self.settings = Settings()
     self.queues = gen_queue_dict()
     self.onion_service = OnionService()
     self.gateway = Gateway()
     self.args = self.user_input, self.window, self.settings, self.queues, self.onion_service, self.gateway
Exemplo n.º 3
0
def input_loop(queues: Dict[bytes, 'Queue[bytes]'], settings: 'Settings',
               gateway: 'Gateway', contact_list: 'ContactList',
               group_list: 'GroupList', master_key: 'MasterKey',
               onion_service: 'OnionService', stdin_fd: int) -> NoReturn:
    """Get input from user and process it accordingly.

    Running this loop as a process allows handling different functions
    including inputs, key exchanges, file loading and assembly packet
    generation, separate from assembly packet output.
    """
    sys.stdin = os.fdopen(stdin_fd)
    window = TxWindow(contact_list, group_list)

    while True:
        with ignored(EOFError, FunctionReturn, KeyboardInterrupt):
            readline.set_completer(
                get_tab_completer(contact_list, group_list, settings, gateway))
            readline.parse_and_bind('tab: complete')

            window.update_window(group_list)

            while not onion_service.is_delivered:
                export_onion_service_data(contact_list, settings,
                                          onion_service, gateway)

            while not contact_list.has_local_contact():
                new_local_key(contact_list, settings, queues)

            while not contact_list.has_contacts():
                add_new_contact(contact_list, group_list, settings, queues,
                                onion_service)

            while not window.is_selected():
                window.select_tx_window(settings, queues, onion_service,
                                        gateway)

            user_input = get_input(window, settings)

            if user_input.type == MESSAGE:
                queue_message(user_input, window, settings, queues)

            elif user_input.type == FILE:
                queue_file(window, settings, queues)

            elif user_input.type == COMMAND:
                process_command(user_input, window, contact_list, group_list,
                                settings, queues, master_key, onion_service,
                                gateway)
Exemplo n.º 4
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)