diff --git a/federation/outbound.py b/federation/outbound.py index 49dc664..e43b7ef 100644 --- a/federation/outbound.py +++ b/federation/outbound.py @@ -63,9 +63,12 @@ def handle_send( :arg entity: Entity object to send. Can be a base entity or a protocol specific one. :arg author_user: User authoring the object. :arg recipients: A list of recipients to delivery to. Each recipient is a dict - containing at minimum the "fid", "public" and "protocol" keys. + containing at minimum the "endpoint", "fid", "public" and "protocol" keys. - For ActivityPub and Diaspora payloads, "fid" should be an URL of the endpoint to deliver to. + For ActivityPub and Diaspora payloads, "endpoint" should be an URL of the endpoint to deliver to. + + The "fid" can be empty for Diaspora payloads. For ActivityPub it should be the recipient + federation ID should the delivery be non-private. The "protocol" should be a protocol name that is known for this recipient. @@ -79,22 +82,26 @@ def handle_send( For example [ { - "fid": "https://domain.tld/receive/users/1234-5678-0123-4567", + "endpoint": "https://domain.tld/receive/users/1234-5678-0123-4567", + "fid": "", "protocol": "diaspora", "public": False, "public_key": , }, { - "fid": "https://domain2.tld/receive/public", + "endpoint": "https://domain2.tld/receive/public", + "fid": "", "protocol": "diaspora", "public": True, }, { - "fid": "https://domain4.tld/sharedinbox/", + "endpoint": "https://domain4.tld/sharedinbox/", + "fid": "https://domain4.tld/profiles/jack/", "protocol": "activitypub", "public": True, }, { + "endpoint": "https://domain4.tld/profiles/jill/inbox", "fid": "https://domain4.tld/profiles/jill", "protocol": "activitypub", "public": False, @@ -119,10 +126,12 @@ def handle_send( } # Flatten to unique recipients + # TODO supply a callable that empties "fid" in the case that public=True unique_recipients = unique_everseen(recipients) # Generate payloads and collect urls for recipient in unique_recipients: + endpoint = recipient["endpoint"] fid = recipient["fid"] public_key = recipient.get("public_key") protocol = recipient["protocol"] @@ -145,7 +154,7 @@ def handle_send( "auth": get_http_authentication(author_user.private_key, f"{author_user.id}#main-key"), "payload": payload, "content_type": 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', - "urls": {fid}, + "urls": {endpoint}, }) elif protocol == "diaspora": if public: @@ -155,7 +164,7 @@ def handle_send( public_payloads[protocol]["payload"] = handle_create_payload( entity, author_user, protocol, parent_user=parent_user, ) - public_payloads["diaspora"]["urls"].add(fid) + public_payloads["diaspora"]["urls"].add(endpoint) else: if not public_key: raise ValueError("handle_send - Diaspora recipient cannot be private without a public key for " @@ -170,7 +179,7 @@ def handle_send( logger.error("handle_send - failed to generate private payload for %s: %s", fid, ex) continue payloads.append({ - "urls": {fid}, "payload": payload, "content_type": "application/json", "auth": None, + "urls": {endpoint}, "payload": payload, "content_type": "application/json", "auth": None, }) # Add public diaspora payload diff --git a/federation/tests/test_outbound.py b/federation/tests/test_outbound.py index d79867b..8a54cab 100644 --- a/federation/tests/test_outbound.py +++ b/federation/tests/test_outbound.py @@ -25,24 +25,29 @@ class TestHandleSend: key = get_dummy_private_key() recipients = [ { - "fid": "https://127.0.0.1/receive/users/1234", "public_key": key.publickey(), "public": False, - "protocol": "diaspora", + "endpoint": "https://127.0.0.1/receive/users/1234", "public_key": key.publickey(), "public": False, + "protocol": "diaspora", "fid": "", }, { - "fid": "https://example.com/receive/public", "public": True, "protocol": "diaspora", + "endpoint": "https://example.com/receive/public", "public": True, "protocol": "diaspora", + "fid": "", }, { - "fid": "https://example.net/receive/public", "public": True, "protocol": "diaspora", + "endpoint": "https://example.net/receive/public", "public": True, "protocol": "diaspora", + "fid": "", }, # Same twice to ensure one delivery only per unique { - "fid": "https://example.net/receive/public", "public": True, "protocol": "diaspora", + "endpoint": "https://example.net/receive/public", "public": True, "protocol": "diaspora", + "fid": "", }, { - "fid": "https://example.net/foobar", "public": False, "protocol": "activitypub", + "endpoint": "https://example.net/foobar/inbox", "fid": "https://example.net/foobar", "public": False, + "protocol": "activitypub", }, { - "fid": "https://example.net/inbox", "public": True, "protocol": "activitypub", + "endpoint": "https://example.net/inbox", "fid": "https://example.net/foobar", "public": True, + "protocol": "activitypub", } ] mock_author = Mock( @@ -59,7 +64,7 @@ class TestHandleSend: # Ensure second call is a private activitypub payload args, kwargs = mock_send.call_args_list[1] - assert args[0] == "https://example.net/foobar" + assert args[0] == "https://example.net/foobar/inbox" assert kwargs['headers'] == { 'Content-Type': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', }