diff --git a/federation/entities/activitypub/mappers.py b/federation/entities/activitypub/mappers.py index 7cfb48e..8d023af 100644 --- a/federation/entities/activitypub/mappers.py +++ b/federation/entities/activitypub/mappers.py @@ -1,3 +1,4 @@ +import logging from typing import List, Callable, Dict, Union from federation.entities.activitypub.entities import ActivitypubFollow, ActivitypubProfile, ActivitypubAccept @@ -5,6 +6,9 @@ from federation.entities.base import Follow, Profile, Accept from federation.entities.mixins import BaseEntity from federation.types import UserType +logger = logging.getLogger("federation") + + MAPPINGS = { "Accept": ActivitypubAccept, "Follow": ActivitypubFollow, @@ -23,10 +27,24 @@ def element_to_objects(payload: Dict) -> List: transformed = transform_attributes(payload, cls) entity = cls(**transformed) + # Add protocol name + entity._source_protocol = "activitypub" + # Save element object to entity for possible later use + entity._source_object = payload if hasattr(entity, "post_receive"): entity.post_receive() + try: + entity.validate() + except ValueError as ex: + logger.error("Failed to validate entity %s: %s", entity, ex, extra={ + "transformed": transformed, + }) + return [] + # Extract mentions + entity._mentions = entity.extract_mentions() + entities.append(entity) return entities diff --git a/federation/tests/entities/activitypub/test_mappers.py b/federation/tests/entities/activitypub/test_mappers.py index 6846021..9782748 100644 --- a/federation/tests/entities/activitypub/test_mappers.py +++ b/federation/tests/entities/activitypub/test_mappers.py @@ -5,7 +5,7 @@ import pytest from federation.entities.activitypub.entities import ActivitypubFollow, ActivitypubAccept, ActivitypubProfile from federation.entities.activitypub.mappers import message_to_objects, get_outbound_entity from federation.entities.base import Accept, Follow, Profile -from federation.tests.fixtures.payloads import ACTIVITYPUB_FOLLOW, ACTIVITYPUB_PROFILE +from federation.tests.fixtures.payloads import ACTIVITYPUB_FOLLOW, ACTIVITYPUB_PROFILE, ACTIVITYPUB_PROFILE_INVALID class TestActivitypubEntityMappersReceive: @@ -180,31 +180,20 @@ class TestActivitypubEntityMappersReceive: assert entity.raw_content == "Important note here" assert entity.entity_type == "Comment" - @pytest.mark.skip + @patch("federation.entities.activitypub.mappers.logger.error") def test_invalid_entity_logs_an_error(self, mock_logger): - entities = message_to_objects(DIASPORA_POST_INVALID, "alice@alice.diaspora.example.org") + entities = message_to_objects(ACTIVITYPUB_PROFILE_INVALID, "http://example.com/1234") assert len(entities) == 0 assert mock_logger.called - @pytest.mark.skip def test_adds_source_protocol_to_entity(self): - entities = message_to_objects(DIASPORA_POST_SIMPLE, "alice@alice.diaspora.example.org") - assert entities[0]._source_protocol == "diaspora" + entities = message_to_objects(ACTIVITYPUB_PROFILE, "http://example.com/1234") + assert entities[0]._source_protocol == "activitypub" - @pytest.mark.skip - def test_source_object(self, mock_validate): - entities = message_to_objects(DIASPORA_POST_COMMENT, "alice@alice.diaspora.example.org", - sender_key_fetcher=Mock()) + def test_source_object(self): + entities = message_to_objects(ACTIVITYPUB_PROFILE, "http://example.com/1234") entity = entities[0] - assert entity._source_object == etree.tostring(etree.fromstring(DIASPORA_POST_COMMENT)) - - @pytest.mark.skip - def test_element_to_objects_calls_sender_key_fetcher(self, mock_validate): - mock_fetcher = Mock() - message_to_objects(DIASPORA_POST_COMMENT, "alice@alice.diaspora.example.org", mock_fetcher) - mock_fetcher.assert_called_once_with( - "alice@alice.diaspora.example.org", - ) + assert entity._source_object == ACTIVITYPUB_PROFILE @pytest.mark.skip def test_element_to_objects_calls_retrieve_remote_profile(self, mock_retrieve, mock_validate): diff --git a/federation/tests/fixtures/payloads/activitypub.py b/federation/tests/fixtures/payloads/activitypub.py index e0a1f35..28aed89 100644 --- a/federation/tests/fixtures/payloads/activitypub.py +++ b/federation/tests/fixtures/payloads/activitypub.py @@ -83,3 +83,19 @@ ACTIVITYPUB_PROFILE = { "url": "https://diaspodon.fr/system/accounts/headers/000/033/155/original/45ae49a08ecc5f27.png?1537060098" } } + +ACTIVITYPUB_PROFILE_INVALID = { + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + ], + "id": None, + "type": "Person", + "name": "Jason Robinson", + "url": "https://diaspodon.fr/@jaywink", + "publicKey": { + "id": "https://diaspodon.fr/users/jaywink#main-key", + "owner": "https://diaspodon.fr/users/jaywink", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwVbaT5wvaZobfIB044ai\nhJg/XooEn2jSTnTY1K4mPmhdqYUmszpdXKp64OwA+f3SBuIUIkLAYUSB9Fu19zh+\nzOsoGI5gvA32DHY1vaqdKnT9gt3jKS5AdQ3bl0t9f4pPkO2I5YtQOWV1FvBcwPXG\nB0dIqj0fTqNK37FmyybrRD6uhjySddklN9gNsULTqYVDa0QSXVswTIW2jQudnNlp\nnEf3SfjlK9J8eKPF3hFK3PNXBTTZ4NydBSL3cVBinU0cFg8lUJOK8RI4qaetrVoQ\neKd7gCTSQ7RZh8kmkYmdlweb+ZtORT6Y5ZsotR8jwhAOFAqCt36B5+LX2UIw68Pk\nOwIDAQAB\n-----END PUBLIC KEY-----\n" + }, +}