Save order of elements for Diaspora relayables to the entities

Refs: diaspora/diaspora_federation#26
merge-requests/130/head
Jason Robinson 2017-05-06 21:23:44 +03:00
rodzic 5309bea06f
commit bf5b4a03b6
5 zmienionych plików z 26 dodań i 4 usunięć

Wyświetl plik

@ -19,6 +19,7 @@ Additionally, Diaspora entity mappers `message_to_objects` and `element_to_objec
* Add source payload object to the entity at `_source_object` when processing it. * Add source payload object to the entity at `_source_object` when processing it.
* Add sender public key to the entity at `_sender_key`, but only if it was used for validating signatures. * Add sender public key to the entity at `_sender_key`, but only if it was used for validating signatures.
* Add support for the new Diaspora payload properties coming in the next protocol version. Old XML payloads are and will be still supported. * Add support for the new Diaspora payload properties coming in the next protocol version. Old XML payloads are and will be still supported.
* `DiasporaComment` and `DiasporaLike` will get the order of elements in the XML payload as a list in `xml_tags`. For implementers who want to recreate payloads for these relayables, this list should be saved for later use.
### Changed ### Changed
* Refactor processing of Diaspora payload XML into entities. Diaspora protocol is dropping the `<XML><post></post></XML>` wrapper for the payloads. Payloads with the wrapper will still be parsed as before. * Refactor processing of Diaspora payload XML into entities. Diaspora protocol is dropping the `<XML><post></post></XML>` wrapper for the payloads. Payloads with the wrapper will still be parsed as before.

Wyświetl plik

@ -32,6 +32,7 @@ class DiasporaEntityMixin(BaseEntity):
class DiasporaRelayableMixin(DiasporaEntityMixin): class DiasporaRelayableMixin(DiasporaEntityMixin):
_xml_tags = []
parent_signature = "" parent_signature = ""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

Wyświetl plik

@ -7,6 +7,7 @@ from federation.entities.base import Image, Relationship, Post, Reaction, Commen
from federation.entities.diaspora.entities import ( from federation.entities.diaspora.entities import (
DiasporaPost, DiasporaComment, DiasporaLike, DiasporaRequest, DiasporaProfile, DiasporaRetraction, DiasporaPost, DiasporaComment, DiasporaLike, DiasporaRequest, DiasporaProfile, DiasporaRetraction,
DiasporaRelayableMixin) DiasporaRelayableMixin)
from federation.protocols.diaspora.signatures import get_element_child_info
from federation.utils.diaspora import retrieve_and_parse_profile from federation.utils.diaspora import retrieve_and_parse_profile
logger = logging.getLogger("federation") logger = logging.getLogger("federation")
@ -74,6 +75,7 @@ def element_to_objects(element, sender_key_fetcher=None):
entity._source_object = element entity._source_object = element
# 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")
if sender_key_fetcher: if sender_key_fetcher:
entity._sender_key = sender_key_fetcher(entity.handle) entity._sender_key = sender_key_fetcher(entity.handle)
else: else:
@ -124,7 +126,7 @@ def message_to_objects(message, sender_key_fetcher=None):
def transform_attributes(attrs, cls): def transform_attributes(attrs, cls):
"""Transform some attribute keys. """Transform some attribute keys.
:param attrs: Properties from the XML :param attrs: Properties from the XML
:type attrs: dict :type attrs: dict
:param cls: Class of the entity :param cls: Class of the entity

Wyświetl plik

@ -5,11 +5,23 @@ from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 from Crypto.Signature import PKCS1_v1_5
def _create_signature_hash(doc): def get_element_child_info(doc, attr):
"""Get information from child elements of this elementas a list since order is important.
Don't include signature tags.
:param doc: XML element
:param attr: Attribute to get from the elements, for example "tag" or "text".
"""
props = [] props = []
for child in doc: for child in doc:
if child.tag not in ["author_signature", "parent_author_signature"]: if child.tag not in ["author_signature", "parent_author_signature"]:
props.append(child.text) props.append(getattr(child, attr))
return props
def _create_signature_hash(doc):
props = get_element_child_info(doc, "text")
content = ";".join(props) content = ";".join(props)
return SHA256.new(content.encode("ascii")) return SHA256.new(content.encode("ascii"))

Wyświetl plik

@ -47,7 +47,7 @@ class TestDiasporaEntityMappersReceive():
assert post.raw_content == "((status message))" assert post.raw_content == "((status message))"
assert post.guid == "((guidguidguidguidguidguidguid))" assert post.guid == "((guidguidguidguidguidguidguid))"
assert post.handle == "alice@alice.diaspora.example.org" assert post.handle == "alice@alice.diaspora.example.org"
assert post.public == False assert post.public is False
assert post.created_at == datetime(2011, 7, 20, 1, 36, 7) assert post.created_at == datetime(2011, 7, 20, 1, 36, 7)
assert post.provider_display_name == "Socialhome" assert post.provider_display_name == "Socialhome"
@ -88,6 +88,9 @@ class TestDiasporaEntityMappersReceive():
assert comment.participation == "comment" assert comment.participation == "comment"
assert comment.raw_content == "((text))" assert comment.raw_content == "((text))"
assert comment.signature == "((signature))" assert comment.signature == "((signature))"
assert comment._xml_tags == [
"guid", "parent_guid", "text", "author",
]
mock_validate.assert_called_once_with() mock_validate.assert_called_once_with()
@patch("federation.entities.diaspora.mappers.DiasporaLike._validate_signatures") @patch("federation.entities.diaspora.mappers.DiasporaLike._validate_signatures")
@ -103,6 +106,9 @@ class TestDiasporaEntityMappersReceive():
assert like.participation == "reaction" assert like.participation == "reaction"
assert like.reaction == "like" assert like.reaction == "like"
assert like.signature == "((signature))" assert like.signature == "((signature))"
assert like._xml_tags == [
"parent_type", "guid", "parent_guid", "positive", "author",
]
mock_validate.assert_called_once_with() mock_validate.assert_called_once_with()
def test_message_to_objects_request(self): def test_message_to_objects_request(self):