# Path: federation/protocols/activitypub/signing.py
# def verify_request_signature(request: RequestType, public_key: Union[str, bytes]):
#     """
#     Verify HTTP signature in request against a public key.
#     """
#     key = encode_if_text(public_key)
#     date_header = request.headers.get("Date")
#     if not date_header:
#         raise ValueError("Rquest Date header is missing")
# 
#     ts = parse_http_date(date_header)
#     dt = datetime.datetime.utcfromtimestamp(ts).replace(tzinfo=pytz.utc)
#     past_delta = datetime.timedelta(hours=24)
#     future_delta = datetime.timedelta(seconds=30)
#     now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
#     if dt < now - past_delta or dt > now + future_delta:
#         raise ValueError("Request Date is too far in future or past")
# 
#     HTTPSignatureHeaderAuth.verify(request, key_resolver=lambda **kwargs: key)
# 
# Path: federation/types.py
# class UserType:
#     id: str = attr.ib()
#     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)
# 
#     # Required only if sending to Matrix protocol
#     mxid: Optional[str] = attr.ib(default=None)
#     # TODO needed?
#     variant: Optional[UserVariant] = 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
# 
# class RequestType:
#     """
#     Emulates structure of a Django HttpRequest for compatibility.
#     """
#     body: Union[str, bytes] = attr.ib()
# 
#     # Required when dealing with incoming AP payloads
#     headers: Dict = attr.ib(default=None)
#     method: str = attr.ib(default=None)
#     url: str = attr.ib(default=None)
# 
# Path: federation/utils/text.py
# def decode_if_bytes(text):
#     try:
#         return text.decode("utf-8")
#     except AttributeError:
#         return text


import json
import logging
import re
from typing import Callable, Tuple, Union, Dict
from Crypto.PublicKey.RSA import RsaKey
from federation.entities.activitypub.enums import ActorType
from federation.entities.mixins import BaseEntity
from federation.protocols.activitypub.signing import verify_request_signature
from federation.types import UserType, RequestType
from federation.utils.text import decode_if_bytes
    actor = None
    get_contact_key = None
    payload = None
    request = None
    user = None

    def build_send(self, entity: BaseEntity, from_user: UserType, to_user_key: RsaKey = None) -> Union[str, Dict]:
        """
        Build POST data for sending out to remotes.

        :param entity: The outbound ready entity for this protocol.
        :param from_user: The user sending this payload. Must have ``private_key`` and ``id`` properties.
        :param to_user_key: (Optional) Public key of user we're sending a private payload to.
        :returns: dict or string depending on if private or public payload.
        """
        if hasattr(entity, "outbound_doc") and entity.outbound_doc is not None:
            # Use pregenerated outbound document
            rendered = entity.outbound_doc
        else:
            rendered = entity.to_as2()
        return rendered

    def extract_actor(self):
        if self.payload.get('type') in ActorType.values():
            self.actor = self.payload.get('id')
        else:
            self.actor = self.payload.get('actor')

    def receive(
            self,

# Path: federation/protocols/activitypub/signing.py
# def verify_request_signature(request: RequestType, public_key: Union[str, bytes]):
#     """
#     Verify HTTP signature in request against a public key.
#     """
#     key = encode_if_text(public_key)
#     date_header = request.headers.get("Date")
#     if not date_header:
#         raise ValueError("Rquest Date header is missing")
# 
#     ts = parse_http_date(date_header)
#     dt = datetime.datetime.utcfromtimestamp(ts).replace(tzinfo=pytz.utc)
#     past_delta = datetime.timedelta(hours=24)
#     future_delta = datetime.timedelta(seconds=30)
#     now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
#     if dt < now - past_delta or dt > now + future_delta:
#         raise ValueError("Request Date is too far in future or past")
# 
#     HTTPSignatureHeaderAuth.verify(request, key_resolver=lambda **kwargs: key)
# 
# Path: federation/types.py
# class UserType:
#     id: str = attr.ib()
#     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)
# 
#     # Required only if sending to Matrix protocol
#     mxid: Optional[str] = attr.ib(default=None)
#     # TODO needed?
#     variant: Optional[UserVariant] = 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
# 
# class RequestType:
#     """
#     Emulates structure of a Django HttpRequest for compatibility.
#     """
#     body: Union[str, bytes] = attr.ib()
# 
#     # Required when dealing with incoming AP payloads
#     headers: Dict = attr.ib(default=None)
#     method: str = attr.ib(default=None)
#     url: str = attr.ib(default=None)
# 
# Path: federation/utils/text.py
# def decode_if_bytes(text):
#     try:
#         return text.decode("utf-8")
#     except AttributeError:
#         return text


# Path: federation/protocols/activitypub/protocol.py
import json
import logging
import re
from typing import Callable, Tuple, Union, Dict
from Crypto.PublicKey.RSA import RsaKey
from federation.entities.activitypub.enums import ActorType
from federation.entities.mixins import BaseEntity
from federation.protocols.activitypub.signing import verify_request_signature
from federation.types import UserType, RequestType
from federation.utils.text import decode_if_bytes

    actor = None
    get_contact_key = None
    payload = None
    request = None
    user = None

    def build_send(self, entity: BaseEntity, from_user: UserType, to_user_key: RsaKey = None) -> Union[str, Dict]:
        """
        Build POST data for sending out to remotes.

        :param entity: The outbound ready entity for this protocol.
        :param from_user: The user sending this payload. Must have ``private_key`` and ``id`` properties.
        :param to_user_key: (Optional) Public key of user we're sending a private payload to.
        :returns: dict or string depending on if private or public payload.
        """
        if hasattr(entity, "outbound_doc") and entity.outbound_doc is not None:
            # Use pregenerated outbound document
            rendered = entity.outbound_doc
        else:
            rendered = entity.to_as2()
        return rendered

    def extract_actor(self):
        if self.payload.get('type') in ActorType.values():
            self.actor = self.payload.get('id')
        else:
            self.actor = self.payload.get('actor')

    def receive(
            self,

            request: RequestType,