示例#1
0
class TestGetOnionAddressFromUser(unittest.TestCase):

    def setUp(self) -> None:
        """Pre-test actions."""
        self.queues = gen_queue_dict()

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

    @mock.patch('builtins.input', side_effect=[nick_to_onion_address('Alice')[:-1]+'a',
                                               nick_to_onion_address('Bob')])
    def test_invalid_onion_address_from_user_gets_sent_to_relay_program(self, _: Any) -> None:
        onion_addres_user = nick_to_onion_address('Alice')

        self.assertEqual(get_onion_address_from_user(onion_addres_user, self.queues),
                         nick_to_onion_address('Bob'))
        self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(), 1)

    @mock.patch('builtins.input', side_effect=[nick_to_onion_address('Alice'),
                                               nick_to_onion_address('Bob')])
    def test_user_or_valid_onion_address_from_user_does_not_get_sent_to_relay_program(self, _: Any) -> None:
        onion_addres_user = nick_to_onion_address('Alice')

        self.assertEqual(get_onion_address_from_user(onion_addres_user, self.queues),
                         nick_to_onion_address('Bob'))
        self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(), 0)
示例#2
0
 def test_input(self, *_: Any) -> None:
     self.queue = self.queues[GUI_INPUT_QUEUE]
     app = GetAccountFromUser(self.queue, nick_to_onion_address('Alice'))
     self.assertIsNone(app.evaluate_account())
     self.assertIsNone(app.evaluate_account())
     self.assertIsNone(app.dismiss_window())
     self.assertEqual(self.queue.get(), nick_to_onion_address('Bob'))
示例#3
0
        def queue_delayer() -> None:
            """Place messages to queue one at a time."""
            time.sleep(0.1)
            queues[C_REQ_MGMT_QUEUE].put(
                (RP_ADD_CONTACT_HEADER, b''.join(list(map(nick_to_pub_key, ['Alice', 'Bob'])))))
            time.sleep(0.1)

            # Test that request from Alice does not appear
            queues[CONTACT_REQ_QUEUE].put((nick_to_onion_address('Alice')))
            time.sleep(0.1)

            # Test that request from Charlie appears
            queues[CONTACT_REQ_QUEUE].put((nick_to_onion_address('Charlie')))
            time.sleep(0.1)

            # Test that another request from Charlie does not appear
            queues[CONTACT_REQ_QUEUE].put((nick_to_onion_address('Charlie')))
            time.sleep(0.1)

            # Remove Alice
            queues[C_REQ_MGMT_QUEUE].put((RP_REMOVE_CONTACT_HEADER, nick_to_pub_key('Alice')))
            time.sleep(0.1)

            # Load settings from queue
            queues[C_REQ_STATE_QUEUE].put(False)
            queues[C_REQ_STATE_QUEUE].put(True)

            # Test that request from Alice is accepted
            queues[CONTACT_REQ_QUEUE].put((nick_to_onion_address('Alice')))
            time.sleep(0.1)

            # Exit test
            queues[UNIT_TEST_QUEUE].put(EXIT)
            queues[CONTACT_REQ_QUEUE].put(nick_to_pub_key('Charlie'))
示例#4
0
 def test_get_list_of_addresses(self) -> None:
     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')])
示例#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)
示例#6
0
    def test_user_or_valid_onion_address_from_user_does_not_get_sent_to_relay_program(
            self, _: Any) -> None:
        onion_addres_user = nick_to_onion_address('Alice')

        self.assertEqual(
            get_onion_address_from_user(onion_addres_user, self.queues),
            nick_to_onion_address('Bob'))
        self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(), 0)
示例#7
0
 def test_contact_selectors(self) -> None:
     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'])
示例#8
0
    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')))
示例#9
0
    def test_show_account_diffs(self, _: Any) -> None:

        self.assert_prints("""\
          ┌──────────────────────────────────────────────────────────┐          
          │       Source Computer received an invalid account.       │          
          │    See arrows below that point to correct characters.    │          
          │                                                          │          
          │ zwp3dykiztmeils2u5eqjtdtx5x3kti5ktjthpkznku3ws5u5fq2bnad │          
          │ ↓↓↓↓↓ ↓↓↓↓↓↓↓↓↓↓↓↓↓↓ ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓  │          
          │ hpcrayuxhrcy2wtpfwgwjibderrvjll6azfr4tqat3eka2m2gbb55bid │          
          └──────────────────────────────────────────────────────────┘          
""", show_value_diffs, 'account',
                           nick_to_onion_address('Alice'),
                           nick_to_onion_address('Bob'),
                           local_test=True)
示例#10
0
 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))
示例#11
0
 def test_validate_group_name(self):
     self.assertEqual(
         validate_group_name('test_group\x1f', self.contact_list,
                             self.group_list),
         "Error: Group name must be printable.")
     self.assertEqual(
         validate_group_name(PADDING_LENGTH * 'a', self.contact_list,
                             self.group_list),
         "Error: Group name must be less than 255 chars long.")
     self.assertEqual(
         validate_group_name(DUMMY_GROUP, self.contact_list,
                             self.group_list),
         "Error: Group name cannot use the name reserved for database padding."
     )
     self.assertEqual(
         validate_group_name(nick_to_onion_address("Alice"),
                             self.contact_list, self.group_list),
         "Error: Group name cannot have the format of an account.")
     self.assertEqual(
         validate_group_name('Alice', self.contact_list, self.group_list),
         "Error: Group name cannot be a nick of contact.")
     self.assertEqual(
         validate_group_name('test_group', self.contact_list,
                             self.group_list),
         "Error: Group with name 'test_group' already exists.")
     self.assertEqual(
         validate_group_name('test_group2', self.contact_list,
                             self.group_list), '')
示例#12
0
    def test_flask_server(self) -> None:
        # Setup
        queues = gen_queue_dict()
        url_token_private_key = X448.generate_private_key()
        url_token_public_key = X448.derive_public_key(
            url_token_private_key).hex()
        url_token = 'a450987345098723459870234509827340598273405983274234098723490285'
        url_token_old = 'a450987345098723459870234509827340598273405983274234098723490286'
        url_token_invalid = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
        onion_pub_key = nick_to_pub_key('Alice')
        onion_address = nick_to_onion_address('Alice')
        packet1 = "packet1"
        packet2 = "packet2"
        packet3 = b"packet3"

        # Test
        app = flask_server(queues, url_token_public_key, unit_test=True)

        with app.test_client() as c:
            # Test root domain returns public key of server.
            resp = c.get('/')
            self.assertEqual(resp.data, url_token_public_key.encode())

            resp = c.get(f'/contact_request/{onion_address}')
            self.assertEqual(b'OK', resp.data)
            self.assertEqual(queues[CONTACT_REQ_QUEUE].qsize(), 1)

            # Test invalid URL token returns empty response
            resp = c.get(f'/{url_token_invalid}/messages/')
            self.assertEqual(b'', resp.data)
            resp = c.get(f'/{url_token_invalid}/files/')
            self.assertEqual(b'', resp.data)

        # Test valid URL token returns all queued messages
        queues[URL_TOKEN_QUEUE].put((onion_pub_key, url_token_old))
        queues[URL_TOKEN_QUEUE].put((onion_pub_key, url_token))
        queues[M_TO_FLASK_QUEUE].put((packet1, onion_pub_key))
        queues[M_TO_FLASK_QUEUE].put((packet2, onion_pub_key))
        queues[F_TO_FLASK_QUEUE].put((packet3, onion_pub_key))

        with app.test_client() as c:
            resp = c.get(f'/{url_token}/messages/')
            self.assertEqual(b'packet1\npacket2', resp.data)

        with app.test_client() as c:
            resp = c.get(f'/{url_token}/files/')
            self.assertEqual(b'packet3', resp.data)

        # Test valid URL token returns nothing as queues are empty
        with app.test_client() as c:
            resp = c.get(f'/{url_token}/messages/')
            self.assertEqual(b'', resp.data)

        with app.test_client() as c:
            resp = c.get(f'/{url_token}/files/')
            self.assertEqual(b'', resp.data)

        # Teardown
        tear_queues(queues)
示例#13
0
 def test_client(self, _) -> None:
     onion_pub_key = nick_to_pub_key('Alice')
     onion_address = nick_to_onion_address('Alice')
     tor_port      = '1337'
     settings      = Gateway()
     sk            = TestClient.url_token_private_key
     self.assertIsNone(client(onion_pub_key, self.queues, sk, tor_port, settings, onion_address, unit_test=True))
     self.assertEqual(self.queues[URL_TOKEN_QUEUE].get(), (onion_pub_key, TestClient.url_token))
示例#14
0
文件: test_misc.py 项目: xprog12/tfc
 def test_validate_account(self) -> None:
     user_account = nick_to_onion_address("Bob")
     self.assertEqual(
         validate_onion_addr(
             nick_to_onion_address("Alice") + 'a', user_account),
         'Error: Invalid account length.')
     self.assertEqual(
         validate_onion_addr(
             nick_to_onion_address("Alice").upper(), user_account),
         'Error: Account must be in lower case.')
     self.assertEqual(
         validate_onion_addr(
             nick_to_onion_address("Alice")[:-1] + 'a', user_account),
         'Checksum error - Check that the entered account is correct.')
     self.assertEqual(
         validate_onion_addr(
             nick_to_onion_address("Alice")[:-1] + '%', user_account),
         'Error: Invalid account format.')
     self.assertEqual(validate_onion_addr(LOCAL_ID, user_account),
                      'Error: Can not add reserved account.')
     self.assertEqual(
         validate_onion_addr(nick_to_onion_address("Bob"), user_account),
         'Error: Can not add own account.')
     self.assertEqual(
         validate_onion_addr(nick_to_onion_address("Alice"), user_account),
         '')
示例#15
0
 def test_validate_account(self):
     user_account = nick_to_onion_address("Bob")
     self.assertEqual(
         validate_onion_addr(nick_to_onion_address("Alice"), user_account),
         '')
     self.assertEqual(
         validate_onion_addr(nick_to_onion_address("Bob"), user_account),
         'Error: Can not add own account.')
     self.assertEqual(
         validate_onion_addr(
             nick_to_onion_address("Alice")[:-1] + 'a', user_account),
         'Checksum error - Check that the entered account is correct.')
     self.assertEqual(
         validate_onion_addr(
             nick_to_onion_address("Alice")[:-1] + '%', user_account),
         'Error: Invalid account format.')
     self.assertEqual(
         validate_onion_addr(
             nick_to_onion_address("Alice") + 'a', user_account),
         'Error: Invalid account format.')
     self.assertEqual(
         validate_onion_addr(
             nick_to_onion_address("Alice")[:-1] + '€', user_account),
         'Error: Invalid account format.')
     self.assertEqual(validate_onion_addr(LOCAL_ID, user_account),
                      'Error: Can not add reserved account.')
示例#16
0
    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)
示例#17
0
class TestInputLoop(unittest.TestCase):

    conf_code = blake2b(nick_to_pub_key('Alice'),
                        digest_size=CONFIRM_CODE_LENGTH).hex()
    input_list = [
        '61',  # Enter Relay confirmation code
        '61',  # Enter Receiver confirmation code
        nick_to_onion_address("Alice"),  # Enter rx-account for new contact
        'Alice',  # Enter nick for contact
        '',  # Enter to default for ECDHE
        VALID_ECDHE_PUB_KEY,  # Enter public key for contact
        'Yes',  # Accept key fingerprints for Alice
        conf_code,  # Confirmation code
        'Alice',  # Select Alice as the recipient
        'Test',  # Send test message
        '/file',  # Open file selection prompt
        '',  # Give empty string to abort
        '/exit'
    ]  # Enter exit command

    def setUp(self) -> None:
        """Pre-test actions."""
        self.settings = Settings(disable_gui_dialog=True)
        self.gateway = Gateway()
        self.contact_list = ContactList()
        self.group_list = GroupList()
        self.master_key = MasterKey()
        self.onion_service = OnionService()
        self.queues = gen_queue_dict()

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

    @mock.patch('builtins.input', side_effect=input_list)
    @mock.patch('os.fdopen', MagicMock())
    @mock.patch('os.getrandom', lambda n, flags: n * b'a')
    @mock.patch('os.urandom', lambda n: n * b'a')
    @mock.patch('shutil.get_terminal_size', return_value=[200, 200])
    @mock.patch('src.transmitter.commands.exit_tfc', side_effect=SystemExit)
    @mock.patch('sys.stdin', MagicMock())
    @mock.patch('time.sleep', return_value=None)
    @mock.patch('os.system', return_value=None)
    def test_input_loop_functions(self, *_: Any) -> None:
        with self.assertRaises(SystemExit):
            self.assertIsNone(
                input_loop(self.queues,
                           self.settings,
                           self.gateway,
                           self.contact_list,
                           self.group_list,
                           self.master_key,
                           self.onion_service,
                           stdin_fd=1))
示例#18
0
class TestGetAccountFromUser(unittest.TestCase):

    def setUp(self) -> None:
        """Pre-test actions."""
        self.queues = gen_queue_dict()

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

    @mock.patch('tkinter.Tk',        MagicMock())
    @mock.patch('tkinter.Entry.get', side_effect=[nick_to_onion_address('Alice'),
                                                  nick_to_onion_address('Bob')])
    def test_input(self, *_: Any) -> None:
        self.queue = self.queues[GUI_INPUT_QUEUE]
        app = GetAccountFromUser(self.queue, nick_to_onion_address('Alice'))
        self.assertIsNone(app.evaluate_account())
        self.assertIsNone(app.evaluate_account())
        self.assertIsNone(app.dismiss_window())
        self.assertEqual(self.queue.get(), nick_to_onion_address('Bob'))
示例#19
0
    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)
示例#20
0
    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"))
示例#21
0
    def test_remove_contact_by_address_or_nick(self) -> None:
        # 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')))
示例#22
0
 def queue_delayer() -> None:
     """Place messages to queue one at a time."""
     time.sleep(0.1)
     queues[TOR_DATA_QUEUE].put(
         ('1234', nick_to_onion_address('Alice')))
     queues[CONTACT_MGMT_QUEUE].put(
         (RP_ADD_CONTACT_HEADER, b''.join([nick_to_pub_key('Alice'), nick_to_pub_key('Bob')]), True))
     time.sleep(0.1)
     queues[CONTACT_MGMT_QUEUE].put(
         (RP_REMOVE_CONTACT_HEADER, b''.join([nick_to_pub_key('Alice'), nick_to_pub_key('Bob')]), True))
     time.sleep(0.1)
     queues[UNIT_TEST_QUEUE].put(EXIT)
     time.sleep(0.1)
     queues[CONTACT_MGMT_QUEUE].put((EXIT, EXIT, EXIT))
示例#23
0
 def test_validate_nick(self):
     self.assertEqual(
         validate_nick("Alice_", (self.contact_list, self.group_list,
                                  nick_to_pub_key("Alice"))), '')
     self.assertEqual(
         validate_nick(254 * "a", (self.contact_list, self.group_list,
                                   nick_to_pub_key("Alice"))), '')
     self.assertEqual(
         validate_nick(255 * "a", (self.contact_list, self.group_list,
                                   nick_to_pub_key("Alice"))),
         'Error: Nick must be shorter than 255 chars.')
     self.assertEqual(
         validate_nick("\x01Alice", (self.contact_list, self.group_list,
                                     nick_to_pub_key("Alice"))),
         'Error: Nick must be printable.')
     self.assertEqual(
         validate_nick('', (self.contact_list, self.group_list,
                            nick_to_pub_key("Alice"))),
         "Error: Nick cannot be empty.")
     self.assertEqual(
         validate_nick('Me', (self.contact_list, self.group_list,
                              nick_to_pub_key("Alice"))),
         "Error: 'Me' is a reserved nick.")
     self.assertEqual(
         validate_nick('-!-', (self.contact_list, self.group_list,
                               nick_to_pub_key("Alice"))),
         "Error: '-!-' is a reserved nick.")
     self.assertEqual(
         validate_nick(LOCAL_ID, (self.contact_list, self.group_list,
                                  nick_to_pub_key("Alice"))),
         "Error: Nick cannot have the format of an account.")
     self.assertEqual(
         validate_nick(nick_to_onion_address('A'),
                       (self.contact_list, self.group_list,
                        nick_to_pub_key("Alice"))),
         "Error: Nick cannot have the format of an account.")
     self.assertEqual(
         validate_nick('Bob', (self.contact_list, self.group_list,
                               nick_to_pub_key("Alice"))),
         'Error: Nick already in use.')
     self.assertEqual(
         validate_nick("Alice", (self.contact_list, self.group_list,
                                 nick_to_pub_key("Alice"))), '')
     self.assertEqual(
         validate_nick("test_group", (self.contact_list, self.group_list,
                                      nick_to_pub_key("Alice"))),
         "Error: Nick cannot be a group name.")
示例#24
0
    def test_flask_server(self) -> None:
        # Setup
        queues = gen_queue_dict()
        url_token_private_key = X448.generate_private_key()
        url_token_public_key = X448.derive_public_key(
            url_token_private_key).hex()
        url_token = 'a450987345098723459870234509827340598273405983274234098723490285'
        url_token_old = 'a450987345098723459870234509827340598273405983274234098723490286'
        url_token_invalid = 'ääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääää'
        onion_pub_key = nick_to_pub_key('Alice')
        onion_address = nick_to_onion_address('Alice')
        packet1 = b"packet1"
        packet2 = b"packet2"
        packet3 = b"packet3"
        test_key = SYMMETRIC_KEY_LENGTH * b'a'

        sub_dir = hashlib.blake2b(
            onion_pub_key, key=test_key,
            digest_size=BLAKE2_DIGEST_LENGTH).hexdigest()

        buf_dir_m = f"{RELAY_BUFFER_OUTGOING_M_DIR}/{sub_dir}"
        buf_dir_f = f"{RELAY_BUFFER_OUTGOING_F_DIR}/{sub_dir}"

        ensure_dir(f"{buf_dir_m}/")
        ensure_dir(f"{buf_dir_f}/")

        packet_list = [packet1, packet2]

        for i, packet in enumerate(packet_list):
            TestFlaskServer.store_test_packet(
                packet, buf_dir_m, RELAY_BUFFER_OUTGOING_MESSAGE + f".{i}",
                test_key)

        TestFlaskServer.store_test_packet(packet3, buf_dir_f,
                                          RELAY_BUFFER_OUTGOING_FILE + '.0',
                                          test_key)

        def queue_delayer() -> None:
            """Place buffer key to queue after a delay."""
            time.sleep(0.1)
            queues[RX_BUF_KEY_QUEUE].put(test_key)

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

        # Test
        app = flask_server(queues, url_token_public_key, unit_test=True)

        # Test valid URL token returns all queued messages
        queues[URL_TOKEN_QUEUE].put((onion_pub_key, url_token_old))
        queues[URL_TOKEN_QUEUE].put((onion_pub_key, url_token))

        with app.test_client() as c:
            # Test root domain returns public key of server.
            resp = c.get('/')
            self.assertEqual(resp.data, url_token_public_key.encode())

            resp = c.get(f'/contact_request/{onion_address}')
            self.assertEqual(b'OK', resp.data)
            self.assertEqual(queues[CONTACT_REQ_QUEUE].qsize(), 1)

            # Test invalid URL token returns empty response
            resp = c.get(f'/{url_token_invalid}/messages/')
            self.assertEqual(b'', resp.data)
            resp = c.get(f'/{url_token_invalid}/files/')
            self.assertEqual(b'', resp.data)

        with app.test_client() as c:
            resp = c.get(f'/{url_token}/messages/')
            self.assertEqual(b'packet1\npacket2', resp.data)

        with app.test_client() as c:
            resp = c.get(f'/{url_token}/files/')
            self.assertEqual(b'packet3', resp.data)

        # Test valid URL token returns nothing as buffers are empty
        with app.test_client() as c:
            resp = c.get(f'/{url_token}/messages/')
            self.assertEqual(b'', resp.data)

        with app.test_client() as c:
            resp = c.get(f'/{url_token}/files/')
            self.assertEqual(b'', resp.data)

        # Teardown
        tear_queues(queues)
示例#25
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)