def test_that__handle_connection_should_send_error_frame_if_payload_golem_message_type_is_unexpected( self): # Prepare frame payload which is Golem message other than TransactionSigningRequest. middleman_message = GolemMessageFrame( payload=Ping(), request_id=99, ) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) raw_message_received = self._prepare_and_execute_handle_connection( raw_message) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=SIGNING_SERVICE_PUBLIC_KEY, ) assertpy.assert_that( deserialized_message.payload).is_instance_of(tuple) assertpy.assert_that(deserialized_message.payload).is_length(2) assertpy.assert_that(deserialized_message.payload[0]).is_equal_to( ErrorCode.UnexpectedMessage) assertpy.assert_that(deserialized_message.request_id).is_equal_to( REQUEST_ID_FOR_RESPONSE_FOR_INVALID_FRAME)
def test_that__handle_connection_should_send_golem_message_signed_transaction_if_warning_daily_threshold_exceeded( self): middleman_message = GolemMessageFrame( payload=self._get_deserialized_transaction_signing_request(), request_id=99, ) middleman_message.payload.value = WARNING_DAILY_THRESHOLD + 1 raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) def handle_connection_wrapper(signing_service, connection, receive_frame_generator): with mock.patch( 'signing_service.signing_service.SigningService._get_signed_transaction', return_value=self._get_deserialized_signed_transaction(), ): with mock.patch( 'signing_service.signing_service.SigningService._add_payload_value_to_daily_transactions_sum' ): signing_service._handle_connection(receive_frame_generator, connection) raw_message_received = self._prepare_and_execute_handle_connection( raw_message, handle_connection_wrapper, ) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=SIGNING_SERVICE_PUBLIC_KEY, ) assertpy.assert_that( deserialized_message.payload).is_instance_of(SignedTransaction)
def test_that__handle_connection_should_send_error_frame_if_frame_signature_is_wrong( self): # Prepare message with wrong signature. middleman_message = GolemMessageFrame( payload=self._get_deserialized_transaction_signing_request(), request_id=99, ) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) first_byte = 2 if raw_message[0] == 0 else raw_message[0] malformed_raw_message = bytes(bytearray([first_byte - 1 ])) + raw_message[1:] raw_message_received = self._prepare_and_execute_handle_connection( malformed_raw_message) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=SIGNING_SERVICE_PUBLIC_KEY, ) assertpy.assert_that( deserialized_message.payload).is_instance_of(tuple) assertpy.assert_that(deserialized_message.payload).is_length(2) assertpy.assert_that(deserialized_message.payload[0]).is_equal_to( ErrorCode.InvalidFrameSignature) assertpy.assert_that(deserialized_message.request_id).is_equal_to( REQUEST_ID_FOR_RESPONSE_FOR_INVALID_FRAME)
def test_that__handle_connection_should_send_error_frame_if_payload_golem_message_type_cannot_be_deserialized( self): # Prepare frame payload which is Golem message that cannot be deserialized. middleman_message = GolemMessageFrame( payload=self._get_deserialized_transaction_signing_request( nonce= 'not_int_nonce_which_will_fail_on_deserialization_causing_message_error' ), request_id=99, ) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) raw_message_received = self._prepare_and_execute_handle_connection( raw_message) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=SIGNING_SERVICE_PUBLIC_KEY, ) assertpy.assert_that( deserialized_message.payload).is_instance_of(tuple) assertpy.assert_that(deserialized_message.payload).is_length(2) assertpy.assert_that(deserialized_message.payload[0]).is_equal_to( ErrorCode.InvalidPayload) assertpy.assert_that(deserialized_message.request_id).is_equal_to( REQUEST_ID_FOR_RESPONSE_FOR_INVALID_FRAME)
def test_that_serializing_and_deserializing_message_with_wrong_payload_type_should_raise_exception( self): middleman_message = GolemMessageFrame(Ping(), self.request_id) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) payload_type_position = FRAME_SIGNATURE_BYTES_LENGTH + FRAME_REQUEST_ID_BYTES_LENGTH invalid_payload_type = 100 # Sanity check for payload type in this case to be between expected bytes assert raw_message[payload_type_position:payload_type_position + 1] == b'\x00' assert invalid_payload_type not in PAYLOAD_TYPE_TO_MIDDLEMAN_MESSAGE_CLASS # Replace bytes with payload length raw_message = ( raw_message[:payload_type_position] + bytes(bytearray([invalid_payload_type])) + raw_message[payload_type_position + FRAME_PAYLOAD_TYPE_LENGTH:]) # Replace message signature new_signature = ecdsa_sign(CONCENT_PRIVATE_KEY, raw_message[FRAME_SIGNATURE_BYTES_LENGTH:]) raw_message_with_new_signature = new_signature + raw_message[ FRAME_SIGNATURE_BYTES_LENGTH:] with pytest.raises(PayloadTypeInvalidMiddlemanProtocolError): AbstractFrame.deserialize(raw_message_with_new_signature, CONCENT_PUBLIC_KEY)
def test_that_receiving_a_series_of_messages_should_be_handled_correctly( self, unused_tcp_port): payload = Ping() middleman_message = GolemMessageFrame(payload, self.request_id) raw_message = escape_encode_raw_message( middleman_message.serialize(private_key=CONCENT_PRIVATE_KEY)) raw_message_with_separator = append_frame_separator(raw_message) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() for _i in range(10): client_socket.send(raw_message_with_separator) split_stream_generator = split_stream(connection=connection) for _i in range(10): raw_message_received = next(split_stream_generator) assertpy.assert_that(raw_message).is_equal_to( raw_message_received)
def test_that_receiving_wrongly_encoded_message_should_return_none( self, unused_tcp_port): middleman_message = GolemMessageFrame(Ping(), self.request_id) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY, ) raw_message_encoded = escape_encode_raw_message(raw_message) raw_message_encoded = raw_message_encoded + ESCAPE_CHARACTER + b'\xff' raw_message_encoded = append_frame_separator(raw_message_encoded) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() client_socket.send(raw_message_encoded) raw_message_received = next( unescape_stream(connection=connection)) assertpy.assert_that(raw_message_received).is_none()
def test_that_sent_data_is_escaped_and_contains_frame_separator(event_loop): frame = GolemMessageFrame(Ping(), 777) expected_data = append_frame_separator( escape_encode_raw_message(frame.serialize(CONCENT_PRIVATE_KEY))) mocked_writer = prepare_mocked_writer() task = _run_test_in_event_loop(event_loop, send_over_stream_async, frame, mocked_writer, CONCENT_PRIVATE_KEY) assert_that(task.done()).is_true() mocked_writer.write.assert_called_once_with(expected_data) mocked_writer.drain.mock.assert_called_once_with()
def test_that_when_frame_with_escaped_sequence_and_separator_is_received_unescaped_frame_is_returned( event_loop): golem_message_frame = GolemMessageFrame(Ping(), 777) data_to_send = escape_encode_raw_message( golem_message_frame.serialize(CONCENT_PRIVATE_KEY) ) + ESCAPE_SEQUENCES[ESCAPE_CHARACTER] + FRAME_SEPARATOR mocked_reader = prepare_mocked_reader(data_to_send) task = _run_test_in_event_loop(event_loop, handle_frame_receive_async, mocked_reader, CONCENT_PUBLIC_KEY) assert_that(task.done()).is_true() mocked_reader.readuntil.mock.assert_called_once_with(FRAME_SEPARATOR) assert_that(task.result()).is_equal_to(golem_message_frame)
def test_that_exceeding_maximum_frame_length_should_treat_exceeded_frame_as_invalid( self, unused_tcp_port): first_middleman_message = GolemMessageFrame(Ping(), self.request_id) first_raw_message = append_frame_separator( escape_encode_raw_message( first_middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY))) second_middleman_message = AuthenticationChallengeFrame( payload=b'', request_id=100, ) second_raw_message = append_frame_separator( escape_encode_raw_message( second_middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY))) assert len(first_raw_message) > len(second_raw_message) + 10 with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() client_socket.send(first_raw_message) client_socket.send(second_raw_message) with mock.patch( 'middleman_protocol.stream.MAXIMUM_FRAME_LENGTH', len(first_raw_message) - 10): raw_message_received = next( unescape_stream(connection=connection)) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=CONCENT_PUBLIC_KEY, ) assertpy.assert_that(deserialized_message.request_id).is_equal_to(100)
def test_that__handle_connection_should_send_error_frame_if_payload_type_is_invalid( self): # Prepare frame with malformed payload_type. middleman_message = GolemMessageFrame( payload=self._get_deserialized_transaction_signing_request(), request_id=99, ) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) payload_type_position = FRAME_SIGNATURE_BYTES_LENGTH + FRAME_REQUEST_ID_BYTES_LENGTH invalid_payload_type = 100 # Replace bytes with payload length. malformed_raw_message = ( raw_message[:payload_type_position] + bytes(bytearray([invalid_payload_type])) + raw_message[payload_type_position + FRAME_PAYLOAD_TYPE_LENGTH:]) # Replace message signature new_signature = ecdsa_sign( CONCENT_PRIVATE_KEY, malformed_raw_message[FRAME_SIGNATURE_BYTES_LENGTH:]) malformed_raw_message_with_new_signature = new_signature + malformed_raw_message[ FRAME_SIGNATURE_BYTES_LENGTH:] raw_message_received = self._prepare_and_execute_handle_connection( malformed_raw_message_with_new_signature) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=SIGNING_SERVICE_PUBLIC_KEY, ) assertpy.assert_that( deserialized_message.payload).is_instance_of(tuple) assertpy.assert_that(deserialized_message.payload).is_length(2) assertpy.assert_that(deserialized_message.payload[0]).is_equal_to( ErrorCode.InvalidFrame) assertpy.assert_that(deserialized_message.request_id).is_equal_to( REQUEST_ID_FOR_RESPONSE_FOR_INVALID_FRAME)
def test_that_receiving_encoded_message_should_decode_on_the_fly( self, unused_tcp_port): middleman_message = GolemMessageFrame(Ping(), self.request_id) raw_message = append_frame_separator( middleman_message.serialize(private_key=CONCENT_PRIVATE_KEY)) raw_message = raw_message[:10] + ESCAPE_CHARACTER + raw_message[ len(ESCAPE_CHARACTER) + 10:] raw_message_encoded = escape_encode_raw_message(raw_message) assert FRAME_SEPARATOR not in raw_message_encoded raw_message_encoded = append_frame_separator(raw_message_encoded) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() client_socket.send(raw_message_encoded) raw_message_received = next( unescape_stream(connection=connection)) assertpy_bytes_starts_with(raw_message, raw_message_received) assertpy.assert_that( len(raw_message_received)).is_greater_than_or_equal_to( FRAME_PAYLOAD_STARTING_BYTE)
def test_that__handle_connection_should_send_error_frame_if_payload_is_invalid( self): # Prepare frame payload which is not Golem message. middleman_message = GolemMessageFrame( payload=Ping(), request_id=99, ) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) malformed_raw_message = ( raw_message[:FRAME_PAYLOAD_STARTING_BYTE] + AbstractFrame.get_frame_format( ).signed_part_of_the_frame.payload.build(b'\x00' * 100)) # Replace message signature new_signature = ecdsa_sign( CONCENT_PRIVATE_KEY, malformed_raw_message[FRAME_SIGNATURE_BYTES_LENGTH:]) malformed_raw_message_with_new_signature = new_signature + malformed_raw_message[ FRAME_SIGNATURE_BYTES_LENGTH:] raw_message_received = self._prepare_and_execute_handle_connection( malformed_raw_message_with_new_signature) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=SIGNING_SERVICE_PUBLIC_KEY, ) assertpy.assert_that( deserialized_message.payload).is_instance_of(tuple) assertpy.assert_that(deserialized_message.payload).is_length(2) assertpy.assert_that(deserialized_message.payload[0]).is_equal_to( ErrorCode.InvalidPayload) assertpy.assert_that(deserialized_message.request_id).is_equal_to( REQUEST_ID_FOR_RESPONSE_FOR_INVALID_FRAME)