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
示例#2
0
 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
示例#3
0
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)
示例#4
0
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,
    ))
示例#5
0
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)
示例#6
0
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)
示例#7
0
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
        )
示例#8
0
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,
        ))
示例#9
0
 def test_handle_receive_raises_on_unidentified_protocol(self):
     payload = RequestType(body="foobar")
     with pytest.raises(NoSuitableProtocolFoundError):
         handle_receive(payload)
示例#10
0
 def test_handle_receive_raises_on_unidentified_protocol(self):
     payload = "foobar"
     with pytest.raises(NoSuitableProtocolFoundError):
         handle_receive(payload)