Ejemplo n.º 1
0
    def test_add_contact(self):
        tx_fingerprint = FINGERPRINT_LENGTH * b'\x03'
        rx_fingerprint = FINGERPRINT_LENGTH * b'\x04'

        self.assertIsNone(
            self.contact_list.add_contact(
                nick_to_pub_key('Faye'), 'Faye', tx_fingerprint,
                rx_fingerprint, KEX_STATUS_UNVERIFIED,
                self.settings.log_messages_by_default,
                self.settings.accept_files_by_default,
                self.settings.show_notifications_by_default))

        # Test new contact was stored by loading
        # the database from file to another object
        contact_list2 = ContactList(MasterKey(), Settings())
        faye = contact_list2.get_contact_by_pub_key(nick_to_pub_key('Faye'))

        self.assertEqual(len(self.contact_list),
                         len(self.real_contact_list) + 1)
        self.assertIsInstance(faye, Contact)

        self.assertEqual(faye.tx_fingerprint, tx_fingerprint)
        self.assertEqual(faye.rx_fingerprint, rx_fingerprint)
        self.assertEqual(faye.kex_status, KEX_STATUS_UNVERIFIED)

        self.assertEqual(faye.log_messages,
                         self.settings.log_messages_by_default)
        self.assertEqual(faye.file_reception,
                         self.settings.accept_files_by_default)
        self.assertEqual(faye.notifications,
                         self.settings.show_notifications_by_default)
Ejemplo n.º 2
0
    def test_add_contact_that_replaces_an_existing_contact(self):
        alice = self.contact_list.get_contact_by_pub_key(
            nick_to_pub_key('Alice'))
        new_nick = 'Alice2'
        new_tx_fingerprint = FINGERPRINT_LENGTH * b'\x03'
        new_rx_fingerprint = FINGERPRINT_LENGTH * b'\x04'

        # Verify that existing nick, kex status and fingerprints are
        # different from those that will replace the existing data
        self.assertNotEqual(alice.nick, new_nick)
        self.assertNotEqual(alice.tx_fingerprint, new_tx_fingerprint)
        self.assertNotEqual(alice.rx_fingerprint, new_rx_fingerprint)
        self.assertNotEqual(alice.kex_status, KEX_STATUS_UNVERIFIED)

        # Make sure each contact setting is opposite from default value
        alice.log_messages = not self.settings.log_messages_by_default
        alice.file_reception = not self.settings.accept_files_by_default
        alice.notifications = not self.settings.show_notifications_by_default

        # Replace the existing contact
        self.assertIsNone(
            self.contact_list.add_contact(
                nick_to_pub_key('Alice'), new_nick, new_tx_fingerprint,
                new_rx_fingerprint, KEX_STATUS_UNVERIFIED,
                self.settings.log_messages_by_default,
                self.settings.accept_files_by_default,
                self.settings.show_notifications_by_default))

        # Load database to another object from
        # file to verify new contact was stored
        contact_list2 = ContactList(MasterKey(), Settings())
        alice = contact_list2.get_contact_by_pub_key(nick_to_pub_key('Alice'))

        # Verify the content of loaded data
        self.assertEqual(len(contact_list2), len(self.real_contact_list))
        self.assertIsInstance(alice, Contact)

        # Test replaced contact replaced nick, fingerprints and kex status
        self.assertEqual(alice.nick, new_nick)
        self.assertEqual(alice.tx_fingerprint, new_tx_fingerprint)
        self.assertEqual(alice.rx_fingerprint, new_rx_fingerprint)
        self.assertEqual(alice.kex_status, KEX_STATUS_UNVERIFIED)

        # Test replaced contact kept settings set
        # to be opposite from default settings
        self.assertNotEqual(alice.log_messages,
                            self.settings.log_messages_by_default)
        self.assertNotEqual(alice.file_reception,
                            self.settings.accept_files_by_default)
        self.assertNotEqual(alice.notifications,
                            self.settings.show_notifications_by_default)
Ejemplo n.º 3
0
class TestContactList(TFCTestCase):
    def setUp(self):
        """Pre-test actions."""
        self.unit_test_dir = cd_unit_test()
        self.master_key = MasterKey()
        self.settings = Settings()
        self.file_name = f'{DIR_USER_DATA}{self.settings.software_operation}_contacts'
        self.contact_list = ContactList(self.master_key, self.settings)
        self.full_contact_list = [
            'Alice', 'Bob', 'Charlie', 'David', 'Eric', LOCAL_ID
        ]
        self.contact_list.contacts = list(
            map(create_contact, self.full_contact_list))
        self.real_contact_list = self.full_contact_list[:]
        self.real_contact_list.remove(LOCAL_ID)

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

    def test_contact_list_iterates_over_contact_objects(self):
        for c in self.contact_list:
            self.assertIsInstance(c, Contact)

    def test_len_returns_the_number_of_contacts_and_excludes_the_local_key(
            self):
        self.assertEqual(len(self.contact_list), len(self.real_contact_list))

    def test_storing_and_loading_of_contacts(self):
        # Test store
        self.contact_list.store_contacts()
        self.assertEqual(
            os.path.getsize(self.file_name), XCHACHA20_NONCE_LENGTH +
            (self.settings.max_number_of_contacts + 1) * CONTACT_LENGTH +
            POLY1305_TAG_LENGTH)

        # Test load
        contact_list2 = ContactList(self.master_key, self.settings)
        self.assertEqual(len(contact_list2), len(self.real_contact_list))
        self.assertEqual(len(contact_list2.contacts),
                         len(self.full_contact_list))
        for c in contact_list2:
            self.assertIsInstance(c, Contact)

    def test_invalid_content_raises_critical_error(self):
        # Setup
        invalid_data = b'a'
        pt_bytes = b''.join([
            c.serialize_c() for c in self.contact_list.contacts +
            self.contact_list._dummy_contacts()
        ])
        ct_bytes = encrypt_and_sign(pt_bytes + invalid_data,
                                    self.master_key.master_key)

        ensure_dir(DIR_USER_DATA)
        with open(self.file_name, 'wb+') as f:
            f.write(ct_bytes)

        # Test
        with self.assertRaises(SystemExit):
            ContactList(self.master_key, self.settings)

    def test_load_of_modified_database_raises_critical_error(self):
        self.contact_list.store_contacts()

        # Test reading works normally
        self.assertIsInstance(ContactList(self.master_key, self.settings),
                              ContactList)

        # Test loading of tampered database raises CriticalError
        tamper_file(self.file_name, tamper_size=1)
        with self.assertRaises(SystemExit):
            ContactList(self.master_key, self.settings)

    def test_generate_dummy_contact(self):
        dummy_contact = ContactList.generate_dummy_contact()
        self.assertIsInstance(dummy_contact, Contact)
        self.assertEqual(len(dummy_contact.serialize_c()), CONTACT_LENGTH)

    def test_dummy_contacts(self):
        dummies = self.contact_list._dummy_contacts()
        self.assertEqual(
            len(dummies),
            self.settings.max_number_of_contacts - len(self.real_contact_list))
        for c in dummies:
            self.assertIsInstance(c, Contact)

    def test_add_contact(self):
        tx_fingerprint = FINGERPRINT_LENGTH * b'\x03'
        rx_fingerprint = FINGERPRINT_LENGTH * b'\x04'

        self.assertIsNone(
            self.contact_list.add_contact(
                nick_to_pub_key('Faye'), 'Faye', tx_fingerprint,
                rx_fingerprint, KEX_STATUS_UNVERIFIED,
                self.settings.log_messages_by_default,
                self.settings.accept_files_by_default,
                self.settings.show_notifications_by_default))

        # Test new contact was stored by loading
        # the database from file to another object
        contact_list2 = ContactList(MasterKey(), Settings())
        faye = contact_list2.get_contact_by_pub_key(nick_to_pub_key('Faye'))

        self.assertEqual(len(self.contact_list),
                         len(self.real_contact_list) + 1)
        self.assertIsInstance(faye, Contact)

        self.assertEqual(faye.tx_fingerprint, tx_fingerprint)
        self.assertEqual(faye.rx_fingerprint, rx_fingerprint)
        self.assertEqual(faye.kex_status, KEX_STATUS_UNVERIFIED)

        self.assertEqual(faye.log_messages,
                         self.settings.log_messages_by_default)
        self.assertEqual(faye.file_reception,
                         self.settings.accept_files_by_default)
        self.assertEqual(faye.notifications,
                         self.settings.show_notifications_by_default)

    def test_add_contact_that_replaces_an_existing_contact(self):
        alice = self.contact_list.get_contact_by_pub_key(
            nick_to_pub_key('Alice'))
        new_nick = 'Alice2'
        new_tx_fingerprint = FINGERPRINT_LENGTH * b'\x03'
        new_rx_fingerprint = FINGERPRINT_LENGTH * b'\x04'

        # Verify that existing nick, kex status and fingerprints are
        # different from those that will replace the existing data
        self.assertNotEqual(alice.nick, new_nick)
        self.assertNotEqual(alice.tx_fingerprint, new_tx_fingerprint)
        self.assertNotEqual(alice.rx_fingerprint, new_rx_fingerprint)
        self.assertNotEqual(alice.kex_status, KEX_STATUS_UNVERIFIED)

        # Make sure each contact setting is opposite from default value
        alice.log_messages = not self.settings.log_messages_by_default
        alice.file_reception = not self.settings.accept_files_by_default
        alice.notifications = not self.settings.show_notifications_by_default

        # Replace the existing contact
        self.assertIsNone(
            self.contact_list.add_contact(
                nick_to_pub_key('Alice'), new_nick, new_tx_fingerprint,
                new_rx_fingerprint, KEX_STATUS_UNVERIFIED,
                self.settings.log_messages_by_default,
                self.settings.accept_files_by_default,
                self.settings.show_notifications_by_default))

        # Load database to another object from
        # file to verify new contact was stored
        contact_list2 = ContactList(MasterKey(), Settings())
        alice = contact_list2.get_contact_by_pub_key(nick_to_pub_key('Alice'))

        # Verify the content of loaded data
        self.assertEqual(len(contact_list2), len(self.real_contact_list))
        self.assertIsInstance(alice, Contact)

        # Test replaced contact replaced nick, fingerprints and kex status
        self.assertEqual(alice.nick, new_nick)
        self.assertEqual(alice.tx_fingerprint, new_tx_fingerprint)
        self.assertEqual(alice.rx_fingerprint, new_rx_fingerprint)
        self.assertEqual(alice.kex_status, KEX_STATUS_UNVERIFIED)

        # Test replaced contact kept settings set
        # to be opposite from default settings
        self.assertNotEqual(alice.log_messages,
                            self.settings.log_messages_by_default)
        self.assertNotEqual(alice.file_reception,
                            self.settings.accept_files_by_default)
        self.assertNotEqual(alice.notifications,
                            self.settings.show_notifications_by_default)

    def test_remove_contact_by_pub_key(self):
        # Verify both contacts exist
        self.assertTrue(self.contact_list.has_pub_key(nick_to_pub_key('Bob')))
        self.assertTrue(
            self.contact_list.has_pub_key(nick_to_pub_key('Charlie')))

        self.assertIsNone(
            self.contact_list.remove_contact_by_pub_key(
                nick_to_pub_key('Bob')))
        self.assertFalse(self.contact_list.has_pub_key(nick_to_pub_key('Bob')))
        self.assertTrue(
            self.contact_list.has_pub_key(nick_to_pub_key('Charlie')))

    def test_remove_contact_by_address_or_nick(self):
        # Verify both contacts exist
        self.assertTrue(self.contact_list.has_pub_key(nick_to_pub_key('Bob')))
        self.assertTrue(
            self.contact_list.has_pub_key(nick_to_pub_key('Charlie')))

        # Test removal with address
        self.assertIsNone(
            self.contact_list.remove_contact_by_address_or_nick(
                nick_to_onion_address('Bob')))
        self.assertFalse(self.contact_list.has_pub_key(nick_to_pub_key('Bob')))
        self.assertTrue(
            self.contact_list.has_pub_key(nick_to_pub_key('Charlie')))

        # Test removal with nick
        self.assertIsNone(
            self.contact_list.remove_contact_by_address_or_nick('Charlie'))
        self.assertFalse(self.contact_list.has_pub_key(nick_to_pub_key('Bob')))
        self.assertFalse(
            self.contact_list.has_pub_key(nick_to_pub_key('Charlie')))

    def test_get_contact_by_pub_key(self):
        self.assertIs(
            self.contact_list.get_contact_by_pub_key(nick_to_pub_key('Bob')),
            self.contact_list.get_contact_by_address_or_nick('Bob'))

    def test_get_contact_by_address_or_nick_returns_the_same_contact_object_with_address_and_nick(
            self):
        for selector in [nick_to_onion_address('Bob'), 'Bob']:
            self.assertIsInstance(
                self.contact_list.get_contact_by_address_or_nick(selector),
                Contact)

        self.assertIs(
            self.contact_list.get_contact_by_address_or_nick('Bob'),
            self.contact_list.get_contact_by_address_or_nick(
                nick_to_onion_address('Bob')))

    def test_get_list_of_contacts(self):
        self.assertEqual(len(self.contact_list.get_list_of_contacts()),
                         len(self.real_contact_list))
        for c in self.contact_list.get_list_of_contacts():
            self.assertIsInstance(c, Contact)

    def test_get_list_of_addresses(self):
        self.assertEqual(self.contact_list.get_list_of_addresses(), [
            nick_to_onion_address('Alice'),
            nick_to_onion_address('Bob'),
            nick_to_onion_address('Charlie'),
            nick_to_onion_address('David'),
            nick_to_onion_address('Eric')
        ])

    def test_get_list_of_nicks(self):
        self.assertEqual(self.contact_list.get_list_of_nicks(),
                         ['Alice', 'Bob', 'Charlie', 'David', 'Eric'])

    def test_get_list_of_pub_keys(self):
        self.assertEqual(self.contact_list.get_list_of_pub_keys(), [
            nick_to_pub_key('Alice'),
            nick_to_pub_key('Bob'),
            nick_to_pub_key('Charlie'),
            nick_to_pub_key('David'),
            nick_to_pub_key('Eric')
        ])

    def test_get_list_of_pending_pub_keys(self):
        # Set key exchange statuses to pending
        for nick in ['Alice', 'Bob']:
            contact = self.contact_list.get_contact_by_address_or_nick(nick)
            contact.kex_status = KEX_STATUS_PENDING

        # Test pending contacts are returned
        self.assertEqual(self.contact_list.get_list_of_pending_pub_keys(),
                         [nick_to_pub_key('Alice'),
                          nick_to_pub_key('Bob')])

    def test_get_list_of_existing_pub_keys(self):
        self.contact_list.get_contact_by_address_or_nick(
            'Alice').kex_status = KEX_STATUS_UNVERIFIED
        self.contact_list.get_contact_by_address_or_nick(
            'Bob').kex_status = KEX_STATUS_VERIFIED
        self.contact_list.get_contact_by_address_or_nick(
            'Charlie').kex_status = KEX_STATUS_HAS_RX_PSK
        self.contact_list.get_contact_by_address_or_nick(
            'David').kex_status = KEX_STATUS_NO_RX_PSK
        self.contact_list.get_contact_by_address_or_nick(
            'Eric').kex_status = KEX_STATUS_PENDING

        self.assertEqual(self.contact_list.get_list_of_existing_pub_keys(), [
            nick_to_pub_key('Alice'),
            nick_to_pub_key('Bob'),
            nick_to_pub_key('Charlie'),
            nick_to_pub_key('David')
        ])

    def test_contact_selectors(self):
        self.assertEqual(self.contact_list.contact_selectors(), [
            nick_to_onion_address('Alice'),
            nick_to_onion_address('Bob'),
            nick_to_onion_address('Charlie'),
            nick_to_onion_address('David'),
            nick_to_onion_address('Eric'), 'Alice', 'Bob', 'Charlie', 'David',
            'Eric'
        ])

    def test_has_contacts(self):
        self.assertTrue(self.contact_list.has_contacts())
        self.contact_list.contacts = []
        self.assertFalse(self.contact_list.has_contacts())

    def test_has_only_pending_contacts(self):
        # Change all to pending
        for contact in self.contact_list.get_list_of_contacts():
            contact.kex_status = KEX_STATUS_PENDING
        self.assertTrue(self.contact_list.has_only_pending_contacts())

        # Change one from pending
        alice = self.contact_list.get_contact_by_address_or_nick('Alice')
        alice.kex_status = KEX_STATUS_UNVERIFIED
        self.assertFalse(self.contact_list.has_only_pending_contacts())

    def test_has_pub_key(self):
        self.contact_list.contacts = []
        self.assertFalse(self.contact_list.has_pub_key(nick_to_pub_key('Bob')))
        self.assertFalse(self.contact_list.has_pub_key(nick_to_pub_key('Bob')))

        self.contact_list.contacts = list(
            map(create_contact, ['Bob', 'Charlie']))
        self.assertTrue(self.contact_list.has_pub_key(nick_to_pub_key('Bob')))
        self.assertTrue(
            self.contact_list.has_pub_key(nick_to_pub_key('Charlie')))

    def test_has_local_contact(self):
        self.contact_list.contacts = []
        self.assertFalse(self.contact_list.has_local_contact())

        self.contact_list.contacts = [create_contact(LOCAL_ID)]
        self.assertTrue(self.contact_list.has_local_contact())

    def test_print_contacts(self):
        self.contact_list.contacts.append(create_contact(LOCAL_ID))
        self.contact_list.get_contact_by_pub_key(
            nick_to_pub_key('Alice')).log_messages = False
        self.contact_list.get_contact_by_pub_key(
            nick_to_pub_key('Alice')).kex_status = KEX_STATUS_PENDING
        self.contact_list.get_contact_by_pub_key(
            nick_to_pub_key('Bob')).notifications = False
        self.contact_list.get_contact_by_pub_key(
            nick_to_pub_key('Charlie')).kex_status = KEX_STATUS_UNVERIFIED
        self.contact_list.get_contact_by_pub_key(
            nick_to_pub_key('Bob')).file_reception = False
        self.contact_list.get_contact_by_pub_key(
            nick_to_pub_key('Bob')).kex_status = KEX_STATUS_VERIFIED
        self.contact_list.get_contact_by_pub_key(nick_to_pub_key(
            'David')).rx_fingerprint = bytes(FINGERPRINT_LENGTH)
        self.contact_list.get_contact_by_pub_key(
            nick_to_pub_key('David')).kex_status = bytes(KEX_STATUS_NO_RX_PSK)
        self.assert_prints(
            CLEAR_ENTIRE_SCREEN + CURSOR_LEFT_UP_CORNER + f"""\

Contact    Account    Logging    Notify    Files     Key Ex
────────────────────────────────────────────────────────────────────────────────
Alice      hpcra      No         Yes       Accept    {ECDHE} (Pending)
Bob        zwp3d      Yes        No        Reject    {ECDHE} (Verified)
Charlie    n2a3c      Yes        Yes       Accept    {ECDHE} (Unverified)
David      u22uy      Yes        Yes       Accept    {PSK}  (No contact key)
Eric       jszzy      Yes        Yes       Accept    {ECDHE} (Verified)


""", self.contact_list.print_contacts)