def test_handle_receive_routes_to_identified_protocol(self): payload = UNENCRYPTED_DIASPORA_PAYLOAD with patch.object( Protocol, "receive", return_value=("*****@*****.**", "<foobar></foobar>") ) as mock_receive, patch( "federation.entities.diaspora.mappers.message_to_objects", return_value=[] ) as mock_message_to_objects: handle_receive(payload) assert mock_receive.called
def test_handle_receive_routes_to_identified_protocol(self): payload = RequestType(body=DIASPORA_PUBLIC_PAYLOAD) with patch.object( Protocol, 'receive', return_value=("*****@*****.**", "<foobar></foobar>")) as mock_receive,\ patch( "federation.entities.diaspora.mappers.message_to_objects", return_value=[]) as mock_message_to_objects: handle_receive(payload) assert mock_receive.called
def receive_task(payload, guid=None): """Process received payload.""" profile = None if guid: try: profile = Profile.objects.get(guid=guid, user__isnull=False) except Profile.DoesNotExist: logger.warning("No local profile found with guid") return try: sender, protocol_name, entities = handle_receive( payload, user=profile, sender_key_fetcher=sender_key_fetcher) logger.debug("sender=%s, protocol_name=%s, entities=%s" % (sender, protocol_name, entities)) except NoSuitableProtocolFoundError: logger.warning("No suitable protocol found for payload") return except NoSenderKeyFoundError: logger.warning( "Could not find a public key for the sender - skipping payload") return except AssertionError: logger.warning("Signature validation failed - skipping payload") return if not entities: logger.warning("No entities in payload") return sender_profile = get_sender_profile(sender) if not sender_profile: return process_entities(entities, profile=sender_profile)
def retrieve_and_parse_content( id: str, guid: str, handle: str, entity_type: str, sender_key_fetcher: Callable[[str], str]=None, ): """Retrieve remote content and return an Entity class instance. This is basically the inverse of receiving an entity. Instead, we fetch it, then call "handle_receive". :param sender_key_fetcher: Function to use to fetch sender public key. If not given, network will be used to fetch the profile and the key. Function must take handle as only parameter and return a public key. :returns: Entity object instance or ``None`` """ if not validate_handle(handle): return _username, domain = handle.split("@") url = get_fetch_content_endpoint(domain, entity_type.lower(), guid) document, status_code, error = fetch_document(url) if status_code == 200: request = RequestType(body=document) _sender, _protocol, entities = handle_receive(request, sender_key_fetcher=sender_key_fetcher) if len(entities) > 1: logger.warning("retrieve_and_parse_content - more than one entity parsed from remote even though we" "expected only one! ID %s", guid) if entities: return entities[0] return elif status_code == 404: logger.warning("retrieve_and_parse_content - remote content %s not found", guid) return if error: raise error raise Exception("retrieve_and_parse_content - unknown problem when fetching document: %s, %s, %s" % ( document, status_code, error, ))
def process(payload): """Open payload and route it to any pods that might be interested in it.""" try: sender, protocol_name, entities = handle_receive( payload, sender_key_fetcher=Profile.get_public_key) logging.debug("sender=%s, protocol_name=%s, entities=%s" % (sender, protocol_name, entities)) except NoSuitableProtocolFoundError: logging.warning("No suitable protocol found for payload") return if protocol_name != "diaspora": logging.warning("Unsupported protocol: %s, sender: %s" % (protocol_name, sender)) return if not entities: logging.warning("No entities in payload") return sent_amount = 0 sent_success = 0 nodes = set() sent_to_nodes = [] entity = None try: for entity in entities: # Diaspora payloads should only have one top level entity. Once we find a suitable one, just start sending if isinstance(entity, SUPPORTED_ENTITIES): nodes = get_send_to_nodes(sender, entity) break # Send out if nodes: logging.info("Sending %s to %s nodes", entity, len(nodes)) for node in nodes: status, error = send_document( url="https://%s/receive/public" % node, data=payload, headers=HEADERS, ) is_success = status in [200, 202] if is_success: sent_success += 1 sent_to_nodes.append(node) sent_amount += 1 update_node(node, is_success) logging.info("Successfully sent to %s nodes", len(sent_to_nodes)) finally: log_worker_receive_statistics(protocol_name, len(entities), sent_amount, sent_success)
def receive_task(request, uuid=None): # type: (RequestType, Optional[str]) -> None """Process received payload.""" profile = None if uuid: try: profile = Profile.objects.get(uuid=uuid, user__isnull=False) except Profile.DoesNotExist: logger.warning("No local profile found with uuid") return try: sender, protocol_name, entities = handle_receive( request, user=profile.federable if profile else None, sender_key_fetcher=sender_key_fetcher, ) logger.debug("sender=%s, protocol_name=%s, entities=%s" % (sender, protocol_name, entities)) preferences = global_preferences_registry.manager() if preferences["admin__log_all_receive_payloads"]: Payload.objects.create( body=request.body, direction="inbound", entities_found=len(entities), headers=request.headers, method=request.method, protocol=protocol_name or "", sender=sender or "", url=request.url, ) except NoSuitableProtocolFoundError: logger.warning("No suitable protocol found for payload") return except NoSenderKeyFoundError: logger.warning( "Could not find a public key for the sender - skipping payload") return except SignatureVerificationError: logger.warning("Signature validation failed - skipping payload") return if not entities: logger.warning("No entities in payload") return process_entities(entities)
def process(payload): """Open payload and route it to any pods that might be interested in it.""" try: sender, protocol_name, entities = handle_receive(payload, skip_author_verification=True) logging.debug("sender=%s, protocol_name=%s, entities=%s" % (sender, protocol_name, entities)) except NoSuitableProtocolFoundError: logging.warning("No suitable protocol found for payload") return if protocol_name != "diaspora": logging.warning("Unsupported protocol: %s, sender: %s" % (protocol_name, sender)) return if not entities: logging.warning("No entities in payload") return sent_amount = 0 sent_success = 0 try: for entity in entities: logging.info("Entity: %s" % entity) # We only care about posts atm if isinstance(entity, SUPPORTED_ENTITIES): sent_to_nodes = [] nodes = get_send_to_nodes(sender, entity) # Send out for node in nodes: status, error = send_document( url="https://%s/receive/public" % node, data={"xml": payload}, headers={"User-Agent": config.USER_AGENT}, ) is_success = status in [200, 202] if is_success: sent_success += 1 sent_to_nodes.append(node) sent_amount += 1 update_node(node, is_success) if sent_to_nodes and isinstance(entity, (DiasporaPost, Image)): save_post_metadata(entity=entity, protocol=protocol_name, hosts=sent_to_nodes) finally: log_worker_receive_statistics( protocol_name, len(entities), sent_amount, sent_success )
def retrieve_and_parse_content(id, sender_key_fetcher=None): """Retrieve remote content and return an Entity class instance. This is basically the inverse of receiving an entity. Instead, we fetch it, then call "handle_receive". :param id: Diaspora URI scheme format ID. :param sender_key_fetcher: Function to use to fetch sender public key. If not given, network will be used to fetch the profile and the key. Function must take handle as only parameter and return a public key. :returns: Entity object instance or ``None`` """ handle, entity_type, guid = parse_diaspora_uri(id) _username, domain = handle.split("@") url = get_fetch_content_endpoint(domain, entity_type, guid) document, status_code, error = fetch_document(url) if status_code == 200: _sender, _protocol, entities = handle_receive( document, sender_key_fetcher=sender_key_fetcher) if len(entities) > 1: logger.warning( "retrieve_and_parse_content - more than one entity parsed from remote even though we" "expected only one! ID %s", id) if entities: return entities[0] return elif status_code == 404: logger.warning( "retrieve_and_parse_content - remote content %s not found", id) return if error: raise error raise Exception( "retrieve_and_parse_content - unknown problem when fetching document: %s, %s, %s" % ( document, status_code, error, ))
def test_handle_receive_raises_on_unidentified_protocol(self): payload = RequestType(body="foobar") with pytest.raises(NoSuitableProtocolFoundError): handle_receive(payload)
def test_handle_receive_raises_on_unidentified_protocol(self): payload = "foobar" with pytest.raises(NoSuitableProtocolFoundError): handle_receive(payload)