class TestGetDataLoop(unittest.TestCase): url_token_private_key_user = X448.generate_private_key() url_token_public_key_user = X448.derive_public_key( url_token_private_key_user) url_token_public_key_contact = X448.derive_public_key( X448.generate_private_key()) url_token = X448.shared_key(url_token_private_key_user, url_token_public_key_contact).hex() class MockResponse(object): """Mock Response object.""" def __init__(self): self.test_no = 0 def iter_lines(self): """Return data depending test number.""" self.test_no += 1 message = b'' # Empty message if self.test_no == 1: pass # Invalid message elif self.test_no == 2: message = MESSAGE_DATAGRAM_HEADER + b'\x1f' # Valid message elif self.test_no == 3: message = MESSAGE_DATAGRAM_HEADER + base64.b85encode( b'test') + b'\n' # Invalid public key elif self.test_no == 4: message = PUBLIC_KEY_DATAGRAM_HEADER + base64.b85encode( (TFC_PUBLIC_KEY_LENGTH - 1) * b'\x01') # Valid public key elif self.test_no == 5: message = PUBLIC_KEY_DATAGRAM_HEADER + base64.b85encode( TFC_PUBLIC_KEY_LENGTH * b'\x01') # Group management headers elif self.test_no == 6: message = GROUP_MSG_INVITE_HEADER elif self.test_no == 7: message = GROUP_MSG_JOIN_HEADER elif self.test_no == 8: message = GROUP_MSG_MEMBER_ADD_HEADER elif self.test_no == 9: message = GROUP_MSG_MEMBER_REM_HEADER elif self.test_no == 10: message = GROUP_MSG_EXIT_GROUP_HEADER # Invalid header elif self.test_no == 11: message = b'\x1f' # RequestException (no remaining data) elif self.test_no == 12: (_ for _ in ()).throw(requests.exceptions.RequestException) return message.split(b'\n') class MockFileResponse(object): """MockFileResponse object.""" def __init__(self, content): self.content = content class Session(object): """Mock session object.""" def __init__(self) -> None: """Create new Session object.""" self.proxies = dict() self.timeout = None self.url = None self.stream = False self.test_no = 0 self.response = TestGetDataLoop.MockResponse() self.url_token = TestGetDataLoop.url_token self.onion_url = 'http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaam2dqd.onion' def get(self, url: str, timeout: int = 0, stream: bool = False) -> Any: """Return data depending on what test is in question.""" self.stream = stream self.timeout = timeout if url == f"{self.onion_url}/{self.url_token}/messages": # Test function recovers from RequestException. if self.test_no == 1: self.test_no += 1 (_ for _ in ()).throw(requests.exceptions.RequestException) if self.test_no >= 2: self.test_no += 1 return self.response elif url == f"{self.onion_url}/{self.url_token}/files": # Test file data is received if self.test_no == 0: self.test_no += 1 return TestGetDataLoop.MockFileResponse(b'test') # Test function recovers from RequestException. if self.test_no > 1: (_ for _ in ()).throw(requests.exceptions.RequestException) @staticmethod def mock_session() -> Session: """Return mock Session object.""" return TestGetDataLoop.Session() def setUp(self): """Pre-test actions.""" self.o_session = requests.session self.queues = gen_queue_dict() requests.session = TestGetDataLoop.mock_session def tearDown(self): """Post-test actions.""" requests.session = self.o_session tear_queues(self.queues) def test_get_data_loop(self): onion_pub_key = bytes(ONION_SERVICE_PUBLIC_KEY_LENGTH) settings = Gateway() onion_addr = pub_key_to_onion_address( bytes(ONION_SERVICE_PUBLIC_KEY_LENGTH)) short_addr = pub_key_to_short_address( bytes(ONION_SERVICE_PUBLIC_KEY_LENGTH)) url_token = TestGetDataLoop.url_token session = TestGetDataLoop.mock_session() self.assertIsNone( get_data_loop(onion_addr, url_token, short_addr, onion_pub_key, self.queues, session, settings)) self.assertIsNone( get_data_loop(onion_addr, url_token, short_addr, onion_pub_key, self.queues, session, settings)) self.assertEqual(self.queues[DST_MESSAGE_QUEUE].qsize(), 2) # Message and file self.assertEqual(self.queues[GROUP_MSG_QUEUE].qsize(), 5) # 5 group management messages
def test_derive_public_key_returns_public_key_with_correct_type_and_size( self): private_key = X448.generate_private_key() public_key = X448.derive_public_key(private_key) self.assertIsInstance(public_key, bytes) self.assertEqual(len(public_key), TFC_PUBLIC_KEY_LENGTH)
def test_generate_private_key_function_returns_private_key_object(self): self.assertIsInstance(X448.generate_private_key(), X448PrivateKey)
def test_x448_private_key_size(self): private_key_bytes = X448.generate_private_key().private_bytes( encoding=Encoding.Raw, format=PrivateFormat.Raw, encryption_algorithm=NoEncryption()) self.assertEqual(len(private_key_bytes), TFC_PRIVATE_KEY_LENGTH)
class TestClient(unittest.TestCase): url_token_private_key = X448.generate_private_key() url_token_public_key = X448.derive_public_key(url_token_private_key) url_token = X448.shared_key(url_token_private_key, url_token_public_key).hex() class MockResponse(object): """Mock Response object.""" def __init__(self, text) -> None: """Create new MockResponse object.""" self.text = text self.content = text class MockSession(object): """Mock Session object.""" def __init__(self) -> None: """Create new MockSession object.""" self.proxies = dict() self.timeout = None self.url = None self.test_no = 0 def get(self, url, timeout=0, stream=False) -> Any: """Mock .get() method.""" self.timeout = timeout # When we reach `get_data_loop` that loads stream, throw exception to close the test. if stream: (_ for _ in ()).throw(requests.exceptions.RequestException) if url.startswith( "http://hpcrayuxhrcy2wtpfwgwjibderrvjll6azfr4tqat3eka2m2gbb55bid.onion/" ): if self.test_no == 0: self.test_no += 1 (_ for _ in ()).throw(requests.exceptions.RequestException) if self.test_no == 1: self.test_no += 1 return TestClient.MockResponse('OK') # Test function recovers from RequestException. if self.test_no == 2: self.test_no += 1 (_ for _ in ()).throw(requests.exceptions.RequestException) # Test function recovers from invalid public key. if self.test_no == 3: self.test_no += 1 return TestClient.MockResponse( ((ONION_SERVICE_PUBLIC_KEY_LENGTH - 1) * b'a').hex()) # Test client prints online/offline messages. if self.test_no < 10: self.test_no += 1 return TestClient.MockResponse('') # Test valid public key moves function to `get_data_loop`. if self.test_no == 10: self.test_no += 1 return TestClient.MockResponse( TestClient.url_token_public_key.hex()) @staticmethod def mock_session() -> MockSession: """Return MockSession object.""" return TestClient.MockSession() def setUp(self) -> None: """Pre-test actions.""" self.o_session = requests.session self.queues = gen_queue_dict() requests.session = TestClient.mock_session def tearDown(self) -> None: """Post-test actions.""" requests.session = self.o_session tear_queues(self.queues) @mock.patch('time.sleep', return_value=None) 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))