kopia lustrzana https://gitlab.com/jaywink/federation
Allow UserType.private_key to be passed in as a string
This allows the UserType object to be serialized to for example redis based background workers. To get the real RsaKey object, use the UserType.rsa_private_key property.mentions
rodzic
3dd18e301e
commit
da2d436fdf
|
@ -48,7 +48,7 @@
|
|||
* The high level `fetchers.retrieve_remote_profile` signature has changed. It now expects as first parameter an `id` which for ActivityPub objects is the URL ID and for Diaspora objects is the handle. Additionally a `sender_key_fetcher` can be passed in as before to optimize public key fetching using a callable.
|
||||
* The generator class `RFC7033Webfinger` now expects instead of an `id` the `handle` and `guid` of the profile.
|
||||
* NodeInfo2 parser now returns the admin user in `handle` format instead of a Diaspora format URL.
|
||||
* The high level inbound and outbound functions `inbound.handle_receive`, `outbound.handle_send` parameter `user` must now receive a `UserType` compatible object. This must have the attributes `id` and `private_key`. If Diaspora support is required then also `handle` and `guid` should exist. The type can be found as a class in `types.UserType`.
|
||||
* The high level inbound and outbound functions `inbound.handle_receive`, `outbound.handle_send` parameter `user` must now receive a `UserType` compatible object. This must have the attribute `id`, and for `handle_send` also `private_key`. If Diaspora support is required then also `handle` and `guid` should exist. The type can be found as a class in `types.UserType`.
|
||||
* The high level inbound function `inbound.handle_receive` first parameter has been changed to `request` which must be a `RequestType` compatible object. This must have the attribute `body` which corrresponds to the old `payload` parameter. For ActivityPub inbound requests the object must also contain `headers`, `method` and `url`.
|
||||
* The outbound function `outbound.handle_send` parameter `recipients` structure has changed. It must now be a list of dictionaries, containing at minimum the following: `endpoint` for the recipient endpoint, `fid` for the recipient federation ID (ActivityPub only), `protocol` for the protocol to use and `public` as a boolean whether the payload should be treated as visible to anyone.
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ def handle_create_payload(
|
|||
mappers = importlib.import_module(f"federation.entities.{protocol_name}.mappers")
|
||||
protocol = importlib.import_module(f"federation.protocols.{protocol_name}.protocol")
|
||||
protocol = protocol.Protocol()
|
||||
outbound_entity = mappers.get_outbound_entity(entity, author_user.private_key)
|
||||
outbound_entity = mappers.get_outbound_entity(entity, author_user.rsa_private_key)
|
||||
if parent_user:
|
||||
outbound_entity.sign_with_parent(parent_user.private_key)
|
||||
outbound_entity.sign_with_parent(parent_user.rsa_private_key)
|
||||
send_as_user = parent_user if parent_user else author_user
|
||||
data = protocol.build_send(entity=outbound_entity, from_user=send_as_user, to_user_key=to_user_key)
|
||||
return data
|
||||
|
@ -156,7 +156,7 @@ def handle_send(
|
|||
logger.error("handle_send - failed to generate payload for %s, %s: %s", fid, endpoint, ex)
|
||||
continue
|
||||
payloads.append({
|
||||
"auth": get_http_authentication(author_user.private_key, f"{author_user.id}#main-key"),
|
||||
"auth": get_http_authentication(author_user.rsa_private_key, f"{author_user.id}#main-key"),
|
||||
"payload": payload,
|
||||
"content_type": 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
"urls": {endpoint},
|
||||
|
|
|
@ -106,7 +106,7 @@ class Protocol:
|
|||
def _get_user_key(self):
|
||||
if not getattr(self.user, "private_key", None):
|
||||
raise EncryptedMessageError("Cannot decrypt private message without user key")
|
||||
return self.user.private_key
|
||||
return self.user.rsa_private_key
|
||||
|
||||
def get_sender(self):
|
||||
return MagicEnvelope.get_sender(self.doc)
|
||||
|
@ -150,7 +150,7 @@ class Protocol:
|
|||
xml = entity.outbound_doc
|
||||
else:
|
||||
xml = entity.to_xml()
|
||||
me = MagicEnvelope(etree.tostring(xml), private_key=from_user.private_key, author_handle=from_user.handle)
|
||||
me = MagicEnvelope(etree.tostring(xml), private_key=from_user.rsa_private_key, author_handle=from_user.handle)
|
||||
rendered = me.render()
|
||||
if to_user_key:
|
||||
return EncryptedPayload.encrypt(rendered, to_user_key)
|
||||
|
|
|
@ -10,15 +10,15 @@ from federation.protocols.diaspora.protocol import Protocol, identify_request
|
|||
from federation.tests.fixtures.keys import PUBKEY, get_dummy_private_key
|
||||
from federation.tests.fixtures.payloads import DIASPORA_PUBLIC_PAYLOAD, DIASPORA_ENCRYPTED_PAYLOAD, \
|
||||
DIASPORA_RESHARE_PAYLOAD
|
||||
from federation.types import RequestType
|
||||
from federation.types import RequestType, UserType
|
||||
|
||||
|
||||
class MockUser:
|
||||
private_key = "foobar"
|
||||
|
||||
def __init__(self, nokey=False):
|
||||
if nokey:
|
||||
self.private_key = None
|
||||
else:
|
||||
self.private_key = get_dummy_private_key()
|
||||
|
||||
|
||||
def mock_get_contact_key(contact):
|
||||
|
@ -113,7 +113,7 @@ class TestDiasporaProtocol(DiasporaTestBase):
|
|||
entity = DiasporaPost()
|
||||
private_key = get_dummy_private_key()
|
||||
outbound_entity = get_outbound_entity(entity, private_key)
|
||||
data = protocol.build_send(outbound_entity, from_user=Mock(
|
||||
data = protocol.build_send(outbound_entity, from_user=UserType(
|
||||
private_key=private_key, id="johnny@localhost",
|
||||
handle="johnny@localhost",
|
||||
))
|
||||
|
@ -133,7 +133,7 @@ class TestDiasporaProtocol(DiasporaTestBase):
|
|||
entity = DiasporaPost()
|
||||
private_key = get_dummy_private_key()
|
||||
outbound_entity = get_outbound_entity(entity, private_key)
|
||||
data = protocol.build_send(outbound_entity, to_user_key="public key", from_user=Mock(
|
||||
data = protocol.build_send(outbound_entity, to_user_key="public key", from_user=UserType(
|
||||
private_key=private_key, id="johnny@localhost",
|
||||
handle="johnny@localhost",
|
||||
))
|
||||
|
@ -151,8 +151,8 @@ class TestDiasporaProtocol(DiasporaTestBase):
|
|||
protocol = self.init_protocol()
|
||||
outbound_doc = etree.fromstring("<xml>foo</xml>")
|
||||
entity = Mock(outbound_doc=outbound_doc)
|
||||
from_user = Mock(
|
||||
id="foobar@domain.tld", private_key="barfoo", handle="foobar@domain.tld",
|
||||
from_user = UserType(
|
||||
id="foobar@domain.tld", private_key=get_dummy_private_key(), handle="foobar@domain.tld",
|
||||
)
|
||||
protocol.build_send(entity, from_user)
|
||||
mock_me.assert_called_once_with(
|
||||
|
@ -162,9 +162,9 @@ class TestDiasporaProtocol(DiasporaTestBase):
|
|||
@patch("federation.protocols.diaspora.protocol.EncryptedPayload.decrypt")
|
||||
def test_get_json_payload_magic_envelope(self, mock_decrypt):
|
||||
protocol = Protocol()
|
||||
protocol.user = MockUser()
|
||||
protocol.user = UserType(id="foobar", private_key=get_dummy_private_key())
|
||||
protocol.get_json_payload_magic_envelope("payload")
|
||||
mock_decrypt.assert_called_once_with(payload="payload", private_key="foobar")
|
||||
mock_decrypt.assert_called_once_with(payload="payload", private_key=get_dummy_private_key())
|
||||
|
||||
@patch.object(Protocol, "get_json_payload_magic_envelope", return_value=etree.fromstring("<foo>bar</foo>"))
|
||||
def test_store_magic_envelope_doc_json_payload(self, mock_store):
|
||||
|
|
|
@ -5,6 +5,7 @@ import pytest
|
|||
from federation.entities.diaspora.entities import DiasporaPost
|
||||
from federation.outbound import handle_create_payload, handle_send
|
||||
from federation.tests.fixtures.keys import get_dummy_private_key
|
||||
from federation.types import UserType
|
||||
from federation.utils.text import encode_if_text
|
||||
|
||||
|
||||
|
@ -50,10 +51,10 @@ class TestHandleSend:
|
|||
"protocol": "activitypub",
|
||||
}
|
||||
]
|
||||
mock_author = Mock(
|
||||
author = UserType(
|
||||
private_key=key, id="foo@example.com", handle="foo@example.com",
|
||||
)
|
||||
handle_send(profile, mock_author, recipients)
|
||||
handle_send(profile, author, recipients)
|
||||
|
||||
# Ensure first call is a private diaspora payload
|
||||
args, kwargs = mock_send.call_args_list[0]
|
||||
|
|
|
@ -2,6 +2,7 @@ from enum import Enum
|
|||
from typing import Optional, Dict, Union
|
||||
|
||||
import attr
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.PublicKey.RSA import RsaKey
|
||||
|
||||
|
||||
|
@ -28,9 +29,15 @@ class ReceiverVariant(Enum):
|
|||
@attr.s(frozen=True)
|
||||
class UserType:
|
||||
id: str = attr.ib()
|
||||
private_key: Optional[RsaKey] = attr.ib(default=None)
|
||||
private_key: Optional[Union[RsaKey, str]] = attr.ib(default=None)
|
||||
receiver_variant: Optional[ReceiverVariant] = attr.ib(default=None)
|
||||
|
||||
# Required only if sending to Diaspora protocol platforms
|
||||
handle: Optional[str] = attr.ib(default=None)
|
||||
guid: Optional[str] = attr.ib(default=None)
|
||||
|
||||
@property
|
||||
def rsa_private_key(self) -> RsaKey:
|
||||
if isinstance(self.private_key, str):
|
||||
return RSA.importKey(self.private_key)
|
||||
return self.private_key
|
||||
|
|
Ładowanie…
Reference in New Issue