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)
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'))
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'))
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')])
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)
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)
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'])
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_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)
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))
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), '')
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)
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))
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), '')
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.')
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)
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))
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'))
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_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')))
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))
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.")
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)
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)