Add receiving user guid to entity for private Diaspora payloads

Required for example to actually use (legacy) relationship retraction.
merge-requests/130/head
Jason Robinson 2017-05-21 22:46:23 +03:00
rodzic dd027d4699
commit d64a2c27a2
5 zmienionych plików z 18 dodań i 8 usunięć

Wyświetl plik

@ -8,9 +8,10 @@
### Added ### Added
* New style Diaspora public payloads are now supported (see [here](https://github.com/diaspora/diaspora_federation/issues/30)). Old style payloads are still supported. Payloads are also still sent out old style. * New style Diaspora public payloads are now supported (see [here](https://github.com/diaspora/diaspora_federation/issues/30)). Old style payloads are still supported. Payloads are also still sent out old style.
* Add new `Follow` base entity and support for the new Diaspora "contact" payload. The simple `Follow` maps to Diaspora contact entity with following/sharing both true or false. Sharing as a separate concept is not currently supported. * Add new `Follow` base entity and support for the new Diaspora "contact" payload. The simple `Follow` maps to Diaspora contact entity with following/sharing both true or false. Sharing as a separate concept is not currently supported.
* Added `_receiving_guid` to all entities. This is filled with `user.guid` if `user` is passed to `federation.inbound.handle_receive` and it has a `guid`. Normally in for example Diaspora, this will always be done in private payloads.
### Fixed ### Fixed
* Legacy Diaspora retraction of sharing/following is now supported correctly. The end result is a `DiasporaRetraction` for entity type `Profile`. * Legacy Diaspora retraction of sharing/following is now supported correctly. The end result is a `DiasporaRetraction` for entity type `Profile`. Since the payload doesn't contain the receiving user for a sharing/following retraction in legacy Diaspora protocol, we store the guid of the user in the entity as `_receiving_guid`, assuming it was passed in for processing.
## [0.11.0] - 2017-05-08 ## [0.11.0] - 2017-05-08

Wyświetl plik

@ -13,6 +13,8 @@ class BaseEntity(object):
_required = [] _required = []
_children = [] _children = []
_allowed_children = () _allowed_children = ()
# If we have a receiver for a private payload, store receiving user guid here
_receiving_guid = ""
_source_protocol = "" _source_protocol = ""
_source_object = None _source_object = None
_sender_key = "" _sender_key = ""

Wyświetl plik

@ -52,7 +52,7 @@ def xml_children_as_dict(node):
return dict((e.tag, e.text) for e in node) return dict((e.tag, e.text) for e in node)
def element_to_objects(element, sender_key_fetcher=None): def element_to_objects(element, sender_key_fetcher=None, user=None):
"""Transform an Element to a list of entities recursively. """Transform an Element to a list of entities recursively.
Possible child entities are added to each entity `_children` list. Possible child entities are added to each entity `_children` list.
@ -60,6 +60,7 @@ def element_to_objects(element, sender_key_fetcher=None):
:param tree: Element :param tree: Element
:param sender_key_fetcher: Function to fetch sender public key. If not given, key will always be fetched :param sender_key_fetcher: Function to fetch sender public key. If not given, key will always be fetched
over network. The function should take sender handle as the only parameter. over network. The function should take sender handle as the only parameter.
:param user: Optional receiving user object. If given, should have a `handle`.
:returns: list of entities :returns: list of entities
""" """
entities = [] entities = []
@ -76,6 +77,9 @@ def element_to_objects(element, sender_key_fetcher=None):
entity._source_protocol = "diaspora" entity._source_protocol = "diaspora"
# Save element object to entity for possible later use # Save element object to entity for possible later use
entity._source_object = element entity._source_object = element
# Save receiving guid to object
if user and hasattr(user, "guid"):
entity._receiving_guid = user.guid
# If relayable, fetch sender key for validation # If relayable, fetch sender key for validation
if issubclass(cls, DiasporaRelayableMixin): if issubclass(cls, DiasporaRelayableMixin):
entity._xml_tags = get_element_child_info(element, "tag") entity._xml_tags = get_element_child_info(element, "tag")
@ -106,24 +110,25 @@ def element_to_objects(element, sender_key_fetcher=None):
return entities return entities
def message_to_objects(message, sender_key_fetcher=None): def message_to_objects(message, sender_key_fetcher=None, user=None):
"""Takes in a message extracted by a protocol and maps it to entities. """Takes in a message extracted by a protocol and maps it to entities.
:param message: XML payload :param message: XML payload
:type message: str :type message: str
:param sender_key_fetcher: Function to fetch sender public key. If not given, key will always be fetched :param sender_key_fetcher: Function to fetch sender public key. If not given, key will always be fetched
over network. The function should take sender handle as the only parameter. over network. The function should take sender handle as the only parameter.
:param user: Optional receiving user object. If given, should have a `handle`.
:returns: list of entities :returns: list of entities
""" """
doc = etree.fromstring(message) doc = etree.fromstring(message)
# Future Diaspora protocol version contains the element at top level # Future Diaspora protocol version contains the element at top level
if doc.tag in TAGS: if doc.tag in TAGS:
return element_to_objects(doc, sender_key_fetcher) return element_to_objects(doc, sender_key_fetcher, user)
# Legacy Diaspora protocol wraps the element in <XML><post></post></XML>, so find the right element # Legacy Diaspora protocol wraps the element in <XML><post></post></XML>, so find the right element
for tag in TAGS: for tag in TAGS:
element = doc.find(".//%s" % tag) element = doc.find(".//%s" % tag)
if element is not None: if element is not None:
return element_to_objects(element, sender_key_fetcher) return element_to_objects(element, sender_key_fetcher, user)
return [] return []

Wyświetl plik

@ -23,7 +23,8 @@ def handle_receive(payload, user=None, sender_key_fetcher=None, skip_author_veri
could actually be a different identity. could actually be a different identity.
:arg payload: Payload blob (str) :arg payload: Payload blob (str)
:arg user: User that will be passed to `protocol.receive` (required on private encrypted content) :arg user: User that will be passed to `protocol.receive` (only required on private encrypted content)
MUST have a `private_key` and `guid` if given.
:arg sender_key_fetcher: Function that accepts sender handle and returns public key (optional) :arg sender_key_fetcher: Function that accepts sender handle and returns public key (optional)
:arg skip_author_verification: Don't verify sender (test purposes, false default) :arg skip_author_verification: Don't verify sender (test purposes, false default)
:returns: Tuple of sender handle, protocol name and list of entity objects :returns: Tuple of sender handle, protocol name and list of entity objects
@ -47,7 +48,7 @@ def handle_receive(payload, user=None, sender_key_fetcher=None, skip_author_veri
raise NoSuitableProtocolFoundError() raise NoSuitableProtocolFoundError()
mappers = importlib.import_module("federation.entities.%s.mappers" % found_protocol.PROTOCOL_NAME) mappers = importlib.import_module("federation.entities.%s.mappers" % found_protocol.PROTOCOL_NAME)
entities = mappers.message_to_objects(message, sender_key_fetcher) entities = mappers.message_to_objects(message, sender_key_fetcher, user)
logger.debug("handle_receive: entities %s", entities) logger.debug("handle_receive: entities %s", entities)
return sender, found_protocol.PROTOCOL_NAME, entities return sender, found_protocol.PROTOCOL_NAME, entities

Wyświetl plik

@ -156,13 +156,14 @@ class TestDiasporaEntityMappersReceive():
assert entity.entity_type == "Post" assert entity.entity_type == "Post"
def test_message_to_objects_retraction_legacy_request(self): def test_message_to_objects_retraction_legacy_request(self):
entities = message_to_objects(DIASPORA_LEGACY_REQUEST_RETRACTION) entities = message_to_objects(DIASPORA_LEGACY_REQUEST_RETRACTION, user=Mock(guid="swfeuihiwehuifhiwheiuf"))
assert len(entities) == 1 assert len(entities) == 1
entity = entities[0] entity = entities[0]
assert isinstance(entity, Retraction) assert isinstance(entity, Retraction)
assert entity.handle == "jaywink@iliketoast.net" assert entity.handle == "jaywink@iliketoast.net"
assert entity.target_guid == "7ed1555bc6ae03db" assert entity.target_guid == "7ed1555bc6ae03db"
assert entity.entity_type == "Profile" assert entity.entity_type == "Profile"
assert entity._receiving_guid == "swfeuihiwehuifhiwheiuf"
def test_message_to_objects_contact(self): def test_message_to_objects_contact(self):
entities = message_to_objects(DIASPORA_CONTACT) entities = message_to_objects(DIASPORA_CONTACT)