def test_signature_overwriting(self): msg = message.p2p.Ping() # First signature generated serialized = msg.serialize() msg2 = message.base.Message.deserialize(serialized, None) self.assertIsNotNone(msg2.sig) # Serialization with default sig_func should succeed msg2.serialize() with self.assertRaises(exceptions.SignatureAlreadyExists): golem_messages.dump(msg, self.ecc.raw_privkey, self.ecc.raw_pubkey)
def setUp(self): super().setUp() deadline_offset = 10 message_timestamp = get_current_utc_timestamp() + deadline_offset self.compute_task_def = ComputeTaskDefFactory() self.compute_task_def['deadline'] = message_timestamp want_to_compute_task = WantToComputeTaskFactory( provider_public_key=encode_hex(PROVIDER_PUBLIC_KEY), ) want_to_compute_task = sign_message(want_to_compute_task, PROVIDER_PRIVATE_KEY) task_to_compute = tasks.TaskToComputeFactory( compute_task_def=self.compute_task_def, requestor_public_key=encode_hex(REQUESTOR_PUBLIC_KEY), requestor_ethereum_public_key=encode_hex( REQUESTOR_ETHERUM_PUBLIC_KEY), want_to_compute_task=want_to_compute_task, price=1, ) task_to_compute.generate_ethsig(REQUESTOR_ETHEREUM_PRIVATE_KEY) task_to_compute.sign_all_promissory_notes( deposit_contract_address=settings.GNT_DEPOSIT_CONTRACT_ADDRESS, private_key=REQUESTOR_ETHEREUM_PRIVATE_KEY, ) self.task_to_compute = load( dump( task_to_compute, REQUESTOR_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY, ), settings.CONCENT_PRIVATE_KEY, REQUESTOR_PUBLIC_KEY, check_time=False, ) report_computed_task = tasks.ReportComputedTaskFactory( task_to_compute=self.task_to_compute) self.report_computed_task = load( dump( report_computed_task, PROVIDER_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY, ), settings.CONCENT_PRIVATE_KEY, PROVIDER_PUBLIC_KEY, check_time=False, ) self.force_report_computed_task = message.concents.ForceReportComputedTask( report_computed_task=self.report_computed_task) self.force_get_task_result = message.concents.ForceGetTaskResult( report_computed_task=self.report_computed_task)
def wrapper( request: HttpRequest, client_message: message.Message, client_public_key: bytes, *args: list, **kwargs: dict, ) -> Union[HttpResponse, JsonResponse]: if not is_given_golem_messages_version_supported_by_concent( request=request): log( logger, f'Wrong version of golem messages. Clients version is {request.META["HTTP_X_Golem_Messages"]}, ' f'Concent version is {settings.GOLEM_MESSAGES_VERSION}.', client_public_key=client_public_key, ) serialized_message = dump( message.concents.ServiceRefused( reason=message.concents.ServiceRefused.REASON. UnsupportedProtocolVersion, ), settings.CONCENT_PRIVATE_KEY, client_public_key, ) return HttpResponse(serialized_message, content_type='application/octet-stream') return view(request, client_message, client_public_key, *args, *kwargs)
def test_deserialization_with_time_verification(self, vft_mock): msg = message.Ping() payload = golem_messages.dump(msg, self.ecc.raw_privkey, self.ecc.raw_pubkey) self.assertEqual(vft_mock.call_count, 0) golem_messages.load(payload, self.ecc.raw_privkey, self.ecc.raw_pubkey) self.assertEqual(vft_mock.call_count, 1)
def setUp(self): super().setUp() deadline_offset = 10 message_timestamp = get_current_utc_timestamp() + deadline_offset compute_task_def = message.ComputeTaskDef() compute_task_def['task_id'] = '8' compute_task_def['subtask_id'] = '8' compute_task_def['deadline'] = message_timestamp task_to_compute = tasks.TaskToComputeFactory( compute_task_def=compute_task_def, requestor_public_key=encode_hex(REQUESTOR_PUBLIC_KEY), provider_public_key=encode_hex(PROVIDER_PUBLIC_KEY), price=0, ) task_to_compute = load( dump( task_to_compute, REQUESTOR_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY, ), settings.CONCENT_PRIVATE_KEY, REQUESTOR_PUBLIC_KEY, check_time=False, ) report_computed_task = tasks.ReportComputedTaskFactory( task_to_compute=task_to_compute) self.force_report_computed_task = message.ForceReportComputedTask( report_computed_task=report_computed_task)
def test_api_view_should_rollback_changes_on_400_error(self): store_subtask( task_id=self.compute_task_def['task_id'], subtask_id=self.compute_task_def['subtask_id'], provider_public_key=hex_to_bytes_convert( self.report_computed_task.task_to_compute.provider_public_key), requestor_public_key=hex_to_bytes_convert( self.report_computed_task.task_to_compute.requestor_public_key ), state=Subtask.SubtaskState.FORCING_RESULT_TRANSFER, next_deadline=(get_current_utc_timestamp() - 10), task_to_compute=self.task_to_compute, report_computed_task=self.report_computed_task, force_get_task_result=self.force_get_task_result, ) self.assertEqual(Client.objects.count(), 2) with mock.patch('core.subtask_helpers.verify_file_status', side_effect=_create_client_and_raise_http400_error_mock ) as _create_client_and_raise_error_mock_function: self.client.post( reverse('core:send'), data=dump(self.force_report_computed_task, PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY), content_type='application/octet-stream', HTTP_X_GOLEM_MESSAGES=settings.GOLEM_MESSAGES_VERSION, ) _create_client_and_raise_error_mock_function.assert_called() self.assertEqual(Client.objects.count(), 2)
def test_request_with_not_allowed_http_method_should_return_405_error( self): """ Tests if request to Concent with will return HTTP 405 error if not allowed HTTP method by view is used. """ raw_message = dump( self.force_report_computed_task, settings.CONCENT_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY, ) @require_golem_message @handle_errors_and_responses(database_name='default') @require_POST def dummy_view(_request, _message, _client_public_key): self.fail() request = self.request_factory.put( "/dummy-url/", content_type='application/octet-stream', data=raw_message, HTTP_X_GOLEM_MESSAGES=settings.GOLEM_MESSAGES_VERSION, ) response = dummy_view(request) # pylint: disable=no-value-for-parameter,assignment-from-no-return self.assertEqual(response.status_code, 405)
def test_golem_messages_version_middleware_should_attach_http_header_to_response( self): """ Tests that response from Concent: * Contains HTTP header 'Concent-Version'. * Header contains version of Concent taken from settings. """ ping_message = message.Ping() serialized_ping_message = dump(ping_message, PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY) with mock.patch( 'concent_api.middleware.ConcentVersionMiddleware._concent_version', '1.0'): response = self.client.post( reverse('core:send'), data=serialized_ping_message, content_type='application/octet-stream', HTTP_X_Golem_Messages=settings.GOLEM_MESSAGES_VERSION, ) self.assertFalse(500 <= response.status_code < 600) self.assertIn('concent-golem-messages-version', response._headers) self.assertEqual(response._headers['concent-version'][0], 'Concent-Version') self.assertEqual(response._headers['concent-version'][1], '1.0')
def test_api_view_should_return_golem_message_as_octet_stream(self): raw_message = dump( self.force_report_computed_task, settings.CONCENT_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY, ) decoded_message = None @require_golem_message @handle_errors_and_responses(database_name='default') def dummy_view(request, _message, _client_public_key): # pylint: disable=unused-argument nonlocal decoded_message decoded_message = _message return None request = self.request_factory.post( "/dummy-url/", content_type='application/octet-stream', data=raw_message, HTTP_X_GOLEM_MESSAGES=settings.GOLEM_MESSAGES_VERSION, ) dummy_view(request) # pylint: disable=no-value-for-parameter self.assertIsInstance(decoded_message, message.concents.ForceReportComputedTask) self.assertEqual(decoded_message, self.force_report_computed_task)
def test_dump_load(self): msg = message.Ping() payload = golem_messages.dump(msg, self.ecc.raw_privkey, self.ecc.raw_pubkey) msg2 = golem_messages.load(payload, self.ecc.raw_privkey, self.ecc.raw_pubkey) self.assertEqual(msg, msg2)
def receive_from_concent( signing_key, public_key, concent_variant: dict, path: str = '/api/v1/receive/') -> typing.Optional[bytes]: concent_receive_url = urljoin(concent_variant['url'], path) headers = { 'Content-Type': 'application/octet-stream', 'X-Golem-Messages': golem_messages.__version__, } authorization_msg = message.concents.ClientAuthorization( client_public_key=public_key, ) data = golem_messages.dump(authorization_msg, signing_key, concent_variant['pubkey']) try: logger.debug( 'receive_from_concent(): GET %r hdr: %r', concent_receive_url, headers, ) response = requests.post( concent_receive_url, data=data, headers=headers, **ssl_kwargs(concent_variant), ) except requests.exceptions.RequestException as e: raise exceptions.ConcentUnavailableError( 'Failed to receive_from_concent() {}'.format(e), ) from e verify_response(response) return response.content or None
def test_golem_messages_version_middleware_should_attach_http_header_to_response( self): """ Tests that response from Concent: * Contains HTTP header 'Concent-Golem-Messages-Version'. * Header contains latest version of golem_messages package. """ ping_message = message.Ping() serialized_ping_message = dump(ping_message, PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY) response = self.client.post( reverse('core:send'), data=serialized_ping_message, content_type='application/octet-stream', ) self.assertFalse(500 <= response.status_code < 600) self.assertIn('concent-golem-messages-version', response._headers) self.assertEqual( response._headers['concent-golem-messages-version'][0], 'Concent-Golem-Messages-Version') self.assertEqual( response._headers['concent-golem-messages-version'][1], __version__)
def test_deserialize_verify_sender(self): msg = message.Hello() data = golem_messages.dump(msg, self.ecc.raw_privkey, None) msg_deserialized = message.base.Message.deserialize( data, lambda d: d, sender_public_key=self.ecc.raw_pubkey) self.assertEqual(msg, msg_deserialized)
def test_deserialize_verify_sender_fails(self): ecc2 = golem_messages.ECCx(None) msg = message.Hello() data = golem_messages.dump(msg, self.ecc.raw_privkey, None) with self.assertRaises(exceptions.InvalidSignature): message.base.Message.deserialize(data, lambda d: d, sender_public_key=ecc2.raw_pubkey)
def setUp(self): super().setUp() deadline_offset = 10 message_timestamp = get_current_utc_timestamp() + deadline_offset self.compute_task_def = ComputeTaskDefFactory() self.compute_task_def['deadline'] = message_timestamp want_to_compute_task = WantToComputeTaskFactory( provider_public_key=encode_hex(PROVIDER_PUBLIC_KEY), ) want_to_compute_task = sign_message(want_to_compute_task, PROVIDER_PRIVATE_KEY) task_to_compute = tasks.TaskToComputeFactory( compute_task_def=self.compute_task_def, requestor_public_key=encode_hex(REQUESTOR_PUBLIC_KEY), want_to_compute_task=want_to_compute_task, price=1, ) self.task_to_compute = load( dump( task_to_compute, REQUESTOR_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY, ), settings.CONCENT_PRIVATE_KEY, REQUESTOR_PUBLIC_KEY, check_time=False, ) report_computed_task = tasks.ReportComputedTaskFactory( task_to_compute=self.task_to_compute) self.report_computed_task = load( dump( report_computed_task, PROVIDER_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY, ), settings.CONCENT_PRIVATE_KEY, PROVIDER_PUBLIC_KEY, check_time=False, ) self.force_report_computed_task = message.concents.ForceReportComputedTask( report_computed_task=self.report_computed_task) self.force_get_task_result = message.concents.ForceGetTaskResult( report_computed_task=self.report_computed_task)
def setUp(self): super().setUp() deadline_offset = 10 message_timestamp = get_current_utc_timestamp() + deadline_offset compute_task_def = message.ComputeTaskDef() compute_task_def['task_id'] = '8' compute_task_def['subtask_id'] = '8' compute_task_def['deadline'] = message_timestamp compute_task_def['extra_data'] = { 'frames': [1], 'output_format': 'PNG', 'scene_file': 'kitten.blend', } task_to_compute = tasks.TaskToComputeFactory( compute_task_def=compute_task_def, requestor_public_key=encode_hex(REQUESTOR_PUBLIC_KEY), provider_public_key=encode_hex(PROVIDER_PUBLIC_KEY), price=0, ) task_to_compute = load( dump( task_to_compute, REQUESTOR_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY, ), settings.CONCENT_PRIVATE_KEY, REQUESTOR_PUBLIC_KEY, check_time=False, ) report_computed_task = tasks.ReportComputedTaskFactory( task_to_compute=task_to_compute) report_computed_task = load( dump( report_computed_task, PROVIDER_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY, ), settings.CONCENT_PRIVATE_KEY, PROVIDER_PUBLIC_KEY, check_time=False, ) self.force_report_computed_task = message.ForceReportComputedTask( report_computed_task=report_computed_task)
def test_that_middleware_does_not_intercept_bad_requests(self): ping_message = message.Ping() serialized_ping_message = dump(ping_message, PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY) response = self.client.post( reverse('core:receive'), data=serialized_ping_message, content_type='application/octet-stream', ) self.assertEqual(response.status_code, 400)
def _get_serialized_force_report_computed_task( self, force_report_computed_task: ForceReportComputedTask, timestamp: Union[str, datetime.datetime, None] = None, provider_private_key: Optional[bytes] = None, ) -> bytes: with freeze_time(timestamp or get_timestamp_string()): return dump( force_report_computed_task, provider_private_key if provider_private_key is not None else self.PROVIDER_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY)
def _get_serialized_reject_report_computed_task( self, reject_report_computed_task: RejectReportComputedTask, timestamp: Union[str, datetime.datetime, None] = None, requestor_private_key: Optional[bytes] = None, ) -> bytes: with freeze_time(timestamp or get_timestamp_string()): return dump( reject_report_computed_task, requestor_private_key if requestor_private_key is not None else self.REQUESTOR_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY)
def send_to_concent(msg: message.base.Message, signing_key: bytes, concent_variant: dict) -> typing.Optional[bytes]: """Sends a message to the concent server :return: Raw reply message, None or exception :rtype: Bytes|None """ logger.debug('send_to_concent(): Updating timestamp msg %r', msg) # Delayed messages are prepared before they're needed # and only sent to Concent if they're not cancelled # before. This can cause a situation where previously # prepared message will be too old to send when enqueued. # Also messages with no delay could have stayed in queue # long enough to eat significant amount of Message Transport Time # SEE: golem_messages.constants header = msg_datastructures.MessageHeader( msg.header.type_, # Using this tricky approach instead of time.time() # because of AppVeyor issues. calendar.timegm(time.gmtime()), msg.header.encrypted, ) msg.header = header logger.debug('send_to_concent(): Encrypting msg %r', msg) # if signature already exists, it must be set to None explicitly if msg.sig is not None: msg.sig = None data = golem_messages.dump(msg, signing_key, concent_variant['pubkey']) logger.debug('send_to_concent(): data: %r', data) concent_post_url = urljoin(concent_variant['url'], '/api/v1/send/') headers = { 'Content-Type': 'application/octet-stream', 'X-Golem-Messages': golem_messages.__version__, } try: logger.debug( 'send_to_concent(): POST %r hdr: %r', concent_post_url, headers, ) response = requests.post( concent_post_url, data=data, headers=headers, **ssl_kwargs(concent_variant), ) except requests.exceptions.RequestException as e: logger.warning('Concent RequestException %r', e) response = e.response verify_response(response) return response.content or None
def test_slots_reselialization_optimization(self, dumps_mock): """Don't reserialize message slots immediately after deserialization""" msg = message.p2p.Tasks() # Choose msg type with SIGN = True payload = golem_messages.dump(msg, self.ecc.raw_privkey, self.ecc.raw_pubkey) # One call for slots and second for hash_header self.assertEqual(dumps_mock.call_count, 2) dumps_mock.reset_mock() golem_messages.load(payload, self.ecc.raw_privkey, self.ecc.raw_pubkey) # One call for hash_header dumps_mock.assert_called_once_with(mock.ANY)
def _send_force_report_computed_task(self): report_computed_task = message.tasks.ReportComputedTask( task_to_compute=self.task_to_compute # pylint: disable=no-member ) force_report_computed_task = message.ForceReportComputedTask( report_computed_task=report_computed_task, ) return self.client.post( reverse('core:send'), data=dump(force_report_computed_task, self.PROVIDER_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY), content_type='application/octet-stream', )
def _get_serialized_force_report_computed_task( self, timestamp = None, force_report_computed_task = None, provider_private_key = None, ): with freeze_time(timestamp or self._get_timestamp_string()): return dump( force_report_computed_task, provider_private_key if provider_private_key is not None else self.PROVIDER_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY )
def _get_serialized_subtask_results_verify( self, timestamp=None, subtask_results_verify=None, provider_private_key=None ): return dump( msg=(subtask_results_verify if subtask_results_verify is not None else self._get_deserialized_subtask_results_verify(timestamp)), privkey=provider_private_key if provider_private_key is not None else self.PROVIDER_PRIVATE_KEY, pubkey=settings.CONCENT_PUBLIC_KEY, )
def _get_serialized_reject_report_computed_task( self, timestamp = None, reject_report_computed_task = None, requestor_private_key = None, ): with freeze_time(timestamp or self._get_timestamp_string()): return dump( reject_report_computed_task, requestor_private_key if requestor_private_key is not None else self.REQUESTOR_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY )
def test_require_golem_auth_message_decorator_should_return_http_400_when_auth_message_not_send( self): dumped_message = dump(self._create_test_ping_message(), CONCENT_PRIVATE_KEY, CONCENT_PUBLIC_KEY) request = self.request_factory.post( "/dummy-url/", content_type='application/octet-stream', data=dumped_message) response = dummy_view_require_golem_auth_message(request) # pylint: disable=no-value-for-parameter self.assertEqual(response.status_code, 400) self.assertIn('error', json.loads(response.content))
def test_hello_version_verify(self, v_mock): msg = message.Hello() serialized = golem_messages.dump( msg, self.ecc.raw_privkey, self.ecc.raw_pubkey, ) golem_messages.load( serialized, self.ecc.raw_privkey, self.ecc.raw_pubkey, ) v_mock.assert_called_once_with(golem_messages.__version__)
def _get_serialized_transaction_signing_request( self, signed_transaction: SignedTransaction, concent_private_key: bytes, public_key: bytes, timestamp: Union[str, datetime.datetime, None] = None, ) -> bytes: return dump( msg=( signed_transaction if signed_transaction is not None else self._get_deserialized_transaction_signing_request(timestamp)), privkey=concent_private_key, pubkey=public_key, )
def _get_serialized_subtask_results_rejected( self, subtask_results_rejected: SubtaskResultsRejected, timestamp: Union[str, datetime.datetime, None] = None, requestor_private_key: Optional[bytes] = None, ) -> bytes: """ Return SubtaskResultsRejected serialized """ with freeze_time(timestamp or get_timestamp_string()): return dump( subtask_results_rejected, requestor_private_key if requestor_private_key is not None else self.REQUESTOR_PRIVATE_KEY, settings.CONCENT_PUBLIC_KEY, )
def _get_serialized_transaction_rejected( self, transaction_rejected: TransactionRejected, concent_private_key: bytes, public_key: bytes, timestamp: Union[str, datetime.datetime, None] = None, ) -> bytes: return dump( msg=( transaction_rejected if transaction_rejected is not None else self._get_deserialized_transaction_signing_request(timestamp)), privkey=concent_private_key, pubkey=public_key, )