Пример #1
0
def sender_key_fetcher(handle):
    """Return the RSA public key for a handle, if found.

    Fetches the key first from a local Profile and if not found, looks for a remote Profile over the network.

    :param handle: Handle of profile
    :type handle: str
    :returns: RSA public key or None
    :rtype: str
    """
    logging.debug("sender_key_fetcher - Checking for handle '%s'", handle)
    try:
        profile = Profile.objects.get(handle=handle, user__isnull=True)
        logging.debug(
            "sender_key_fetcher - Handle %s already exists as a profile",
            handle)
    except Profile.DoesNotExist:
        logging.debug(
            "sender_key_fetcher - Handle %s was not found, fetching from remote",
            handle)
        remote_profile = retrieve_remote_profile(handle)
        if not remote_profile:
            logger.warning(
                "Remote profile %s for sender key not found locally or remotely.",
                handle)
            return None
        # We might as well create the profile locally here since we'll need it again soon
        logging.debug("sender_key_fetcher - Creating %s from remote profile",
                      handle)
        Profile.from_remote_profile(remote_profile)
        return remote_profile.public_key
    else:
        return profile.rsa_public_key
Пример #2
0
def process_entities(entities: List):
    """Process a list of entities."""
    for entity in entities:
        logger.info("Entity: %s", entity)
        # noinspection PyProtectedMember
        logger.info("Receivers: %s", entity._receivers)
        sender_id = entity.id if isinstance(entity,
                                            base.Profile) else entity.actor_id
        profile = get_sender_profile(sender_id)
        if not profile:
            logger.warning("No sender profile for entity %s, skipping", entity)
            continue
        try:
            if isinstance(entity, base.Post):
                process_entity_post(entity, profile)
            elif isinstance(entity, base.Retraction):
                process_entity_retraction(entity, profile)
            elif isinstance(entity, base.Comment):
                process_entity_comment(entity, profile)
            elif isinstance(entity, base.Follow):
                process_entity_follow(entity, profile)
            elif isinstance(entity, base.Profile):
                Profile.from_remote_profile(entity)
            elif isinstance(entity, base.Share):
                process_entity_share(entity, profile)
        except Exception as ex:
            logger.exception("Failed to handle %s: %s", entity.id, ex)
Пример #3
0
def process_entities(entities):
    """Process a list of entities."""
    for entity in entities:
        logger.info("Entity: %s", entity)
        profile = get_sender_profile(entity.handle)
        if not profile:
            logger.warning("No sender profile for entity %s, skipping" %
                           entity)
            continue
        try:
            if isinstance(entity, base.Post):
                process_entity_post(entity, profile)
            elif isinstance(entity, base.Retraction):
                process_entity_retraction(entity, profile)
            elif isinstance(entity, base.Comment):
                process_entity_comment(entity, profile)
            elif isinstance(entity, base.Relationship):
                process_entity_relationship(entity, profile)
            elif isinstance(entity, base.Follow):
                process_entity_follow(entity, profile)
            elif isinstance(entity, base.Profile):
                Profile.from_remote_profile(entity)
            elif isinstance(entity, base.Share):
                process_entity_share(entity, profile)
        except Exception as ex:
            logger.exception("Failed to handle %s: %s", entity.guid, ex)
Пример #4
0
    def test_from_remote_profile(self):
        remote_profile = BaseProfileFactory(public=False)
        profile = Profile.from_remote_profile(remote_profile)
        self.assertEqual(profile.guid, remote_profile.guid)
        self.assertEqual(profile.handle, remote_profile.handle)
        self.assertEqual(profile.name, remote_profile.name)
        self.assertEqual(profile.visibility, Visibility.LIMITED)
        self.assertEqual(profile.image_url_large, remote_profile.image_urls["large"])
        self.assertEqual(profile.image_url_medium, remote_profile.image_urls["medium"])
        self.assertEqual(profile.image_url_small, remote_profile.image_urls["small"])
        self.assertEqual(profile.location, remote_profile.location)
        self.assertEqual(profile.email, remote_profile.email)
        self.assertEqual(profile.rsa_public_key, remote_profile.public_key)

        # Update to public
        remote_profile_update = BaseProfileFactory(public=True, guid=remote_profile.guid, handle=remote_profile.handle)
        profile = Profile.from_remote_profile(remote_profile_update)
        self.assertEqual(profile.guid, remote_profile.guid)
        self.assertEqual(profile.handle, remote_profile.handle)
        self.assertEqual(profile.visibility, Visibility.PUBLIC)

        # Make sure public key doesn't get deleted if it doesn't have a value
        public_key = profile.rsa_public_key
        assert public_key
        remote_profile_update = BaseProfileFactory(public_key="", guid=remote_profile.guid,
                                                   handle=remote_profile.handle)
        profile = Profile.from_remote_profile(remote_profile_update)
        self.assertEqual(profile.rsa_public_key, public_key)
        remote_profile_update = BaseProfileFactory(public_key=None, guid=remote_profile.guid,
                                                   handle=remote_profile.handle)
        profile = Profile.from_remote_profile(remote_profile_update)
        self.assertEqual(profile.rsa_public_key, public_key)
Пример #5
0
    def get(self, request, *args, **kwargs):
        """See if we have a direct match. If so redirect, if not, search.

        Try fetching a remote profile if the search term is a handle.
        """
        try:
            q = safe_text(request.GET.get("q"))
            if q:
                q = q.strip().lower()
            validate_email(q)
        except ValidationError:
            pass
        else:
            profile = None
            try:
                profile = Profile.objects.visible_for_user(
                    request.user).get(handle=q)
            except Profile.DoesNotExist:
                # Try a remote search
                remote_profile = retrieve_remote_profile(q)
                if remote_profile:
                    profile = Profile.from_remote_profile(remote_profile)
            if profile:
                return redirect(
                    reverse("users:profile-detail",
                            kwargs={"guid": profile.guid}))
        return super().get(request, *args, **kwargs)
Пример #6
0
def get_sender_profile(sender: str) -> Optional[Profile]:
    """Get or create sender profile.

    Fetch it from federation layer if necessary or if the public key is empty for some reason.
    """
    try:
        logger.debug("get_sender_profile - looking from local db using %s",
                     sender)
        sender_profile = Profile.objects.fed(sender).exclude(
            rsa_public_key="").get()
    except Profile.DoesNotExist:
        logger.debug(
            "get_sender_profile - %s was not found, fetching from remote",
            sender)
        remote_profile = retrieve_remote_profile(sender)
        if not remote_profile:
            logger.warning(
                "get_sender_profile - Remote profile %s not found locally or remotely.",
                sender)
            return
        sender_profile = Profile.from_remote_profile(remote_profile)
    else:
        if sender_profile.is_local:
            logger.warning("get_sender_profile - %s is local! Skip.", sender)
            return
    return sender_profile
Пример #7
0
    def get(self, request, *args, **kwargs):
        """See if we have a direct match. If so redirect, if not, search.

        Try fetching a remote profile if the search term is a handle.
        """
        q = safe_text(request.GET.get("q"))
        if q:
            q = q.strip().lower()
        if validate_handle(q):
            profile = None
            try:
                profile = Profile.objects.visible_for_user(
                    request.user).get(handle=q)
            except Profile.DoesNotExist:
                # Try a remote search
                try:
                    remote_profile = retrieve_remote_profile(q)
                except (AttributeError, ValueError,
                        xml.parsers.expat.ExpatError):
                    # Catch various errors parsing the remote profile
                    return super().get(request, *args, **kwargs)
                if remote_profile:
                    profile = Profile.from_remote_profile(remote_profile)
            if profile:
                return redirect(
                    reverse("users:profile-detail",
                            kwargs={"guid": profile.guid}))
        try:
            return super().get(request, *args, **kwargs)
        except QueryError:
            # Re-render the form
            messages.warning(
                self.request,
                _("Search string is invalid, please try another one."))
            return HttpResponseRedirect(self.get_success_url())
Пример #8
0
 def test_from_remote_profile_absolute_image_url(self):
     remote_profile = BaseProfileFactory(public=False)
     remote_profile.image_urls["small"] = "https://example1.com/sm"
     remote_profile.image_urls["medium"] = "https://example2.com/me"
     remote_profile.image_urls["large"] = "https://example3.com/lg"
     profile = Profile.from_remote_profile(remote_profile)
     self.assertEqual(profile.image_url_small, "https://example1.com/sm")
     self.assertEqual(profile.image_url_medium, "https://example2.com/me")
     self.assertEqual(profile.image_url_large, "https://example3.com/lg")
Пример #9
0
 def test_from_remote_profile_absolute_image_url(self):
     remote_profile = BaseProfileFactory(public=False)
     remote_profile.image_urls["small"] = "https://example1.com/sm"
     remote_profile.image_urls["medium"] = "https://example2.com/me"
     remote_profile.image_urls["large"] = "https://example3.com/lg"
     profile = Profile.from_remote_profile(remote_profile)
     self.assertEqual(profile.image_url_small, "https://example1.com/sm")
     self.assertEqual(profile.image_url_medium, "https://example2.com/me")
     self.assertEqual(profile.image_url_large, "https://example3.com/lg")
Пример #10
0
 def test_from_remote_profile_relative_image_url(self):
     remote_profile = BaseProfileFactory(public=False)
     remote_profile.handle = "foo@localhost"
     remote_profile.image_urls["small"] = "/sm"
     remote_profile.image_urls["medium"] = "/me"
     remote_profile.image_urls["large"] = "/lg"
     profile = Profile.from_remote_profile(remote_profile)
     self.assertEqual(profile.image_url_small, "https://localhost/sm")
     self.assertEqual(profile.image_url_medium, "https://localhost/me")
     self.assertEqual(profile.image_url_large, "https://localhost/lg")
Пример #11
0
 def test_from_remote_profile_relative_image_url(self):
     remote_profile = BaseProfileFactory(public=False)
     remote_profile.handle = "*****@*****.**"
     remote_profile.image_urls["small"] = "/sm"
     remote_profile.image_urls["medium"] = "/me"
     remote_profile.image_urls["large"] = "/lg"
     profile = Profile.from_remote_profile(remote_profile)
     self.assertEqual(profile.image_url_small, "https://example.com/sm")
     self.assertEqual(profile.image_url_medium, "https://example.com/me")
     self.assertEqual(profile.image_url_large, "https://example.com/lg")
Пример #12
0
    def test_from_remote_profile(self):
        remote_profile = BaseProfileFactory(public=False)
        profile = Profile.from_remote_profile(remote_profile)
        self.assertEqual(profile.fid, remote_profile.id)
        self.assertEqual(profile.name, remote_profile.name)
        self.assertEqual(profile.visibility, Visibility.PUBLIC)
        self.assertEqual(profile.image_url_large, remote_profile.image_urls["large"])
        self.assertEqual(profile.image_url_medium, remote_profile.image_urls["medium"])
        self.assertEqual(profile.image_url_small, remote_profile.image_urls["small"])
        self.assertEqual(profile.location, remote_profile.location)
        self.assertEqual(profile.email, remote_profile.email)
        self.assertEqual(profile.rsa_public_key, remote_profile.public_key)

        # Make sure public key doesn't get deleted if it doesn't have a value
        public_key = profile.rsa_public_key
        assert public_key
        remote_profile_update = BaseProfileFactory(public_key="", id=remote_profile.id)
        profile = Profile.from_remote_profile(remote_profile_update)
        self.assertEqual(profile.rsa_public_key, public_key)
        remote_profile_update = BaseProfileFactory(public_key=None, id=remote_profile.id)
        profile = Profile.from_remote_profile(remote_profile_update)
        self.assertEqual(profile.rsa_public_key, public_key)
Пример #13
0
def process_entities(entities, receiving_profile=None):
    """Process a list of entities."""
    for entity in entities:
        logger.info("Entity: %s", entity)
        sender_id = entity.id if isinstance(entity, base.Profile) else entity.actor_id
        profile = get_sender_profile(sender_id)
        if not profile:
            logger.warning("No sender profile for entity %s, skipping", entity)
            continue
        try:
            if isinstance(entity, base.Post):
                process_entity_post(entity, profile, receiving_profile=receiving_profile)
            elif isinstance(entity, base.Retraction):
                process_entity_retraction(entity, profile)
            elif isinstance(entity, base.Comment):
                process_entity_comment(entity, profile, receiving_profile=receiving_profile)
            elif isinstance(entity, base.Follow):
                process_entity_follow(entity, profile)
            elif isinstance(entity, base.Profile):
                Profile.from_remote_profile(entity)
            elif isinstance(entity, base.Share):
                process_entity_share(entity, profile)
        except Exception as ex:
            logger.exception("Failed to handle %s: %s", entity.id, ex)
Пример #14
0
def get_sender_profile(sender):
    """Get or create sender profile.

    Fetch it from federation layer if necessary.
    """
    try:
        sender_profile = Profile.objects.get(handle=sender)
    except Profile.DoesNotExist:
        remote_profile = retrieve_remote_profile(sender)
        if not remote_profile:
            logger.warning("Remote profile %s not found locally or remotely.",
                           sender)
            return
        sender_profile = Profile.from_remote_profile(remote_profile)
    return sender_profile
Пример #15
0
def get_sender_profile(sender):
    """Get or create sender profile.

    Fetch it from federation layer if necessary or if the public key is empty for some reason.
    """
    try:
        sender_profile = Profile.objects.exclude(rsa_public_key="").get(
            handle=sender)
    except Profile.DoesNotExist:
        remote_profile = retrieve_remote_profile(sender)
        if not remote_profile:
            logger.warning("Remote profile %s not found locally or remotely.",
                           sender)
            return
        sender_profile = Profile.from_remote_profile(remote_profile)
    return sender_profile
Пример #16
0
    def get(self, request, *args, **kwargs):
        """See if we have a direct match. If so redirect, if not, search.

        Try fetching a remote profile if the search term is a handle or fid.
        """
        q = safe_text(request.GET.get("q"))
        if q:
            q = q.strip().lower()
        self.q = q
        # Check if direct tag matches
        if q.startswith('#'):
            try:
                tag = Tag.objects.filter(name=q[1:]).annotate(
                    content_count=Count('contents')).filter(
                        content_count__gt=0).get()
            except Tag.DoesNotExist:
                pass
            else:
                return redirect(tag.get_absolute_url())
        # Check if profile matches
        profile = None
        try:
            profile = Profile.objects.visible_for_user(
                request.user).fed(q).get()
        except Profile.DoesNotExist:
            # Try a remote search
            # TODO currently only if diaspora handle
            if validate_handle(q):
                try:
                    remote_profile = retrieve_remote_profile(q)
                except (AttributeError, ValueError,
                        xml.parsers.expat.ExpatError):
                    # Catch various errors parsing the remote profile
                    return super().get(request, *args, **kwargs)
                if remote_profile:
                    profile = Profile.from_remote_profile(remote_profile)
        if profile:
            return redirect(
                reverse("users:profile-detail", kwargs={"uuid": profile.uuid}))
        try:
            return super().get(request, *args, **kwargs)
        except QueryError:
            # Re-render the form
            messages.warning(
                self.request,
                _("Search string is invalid, please try another one."))
            return HttpResponseRedirect(self.get_success_url())
Пример #17
0
    def get(self, request, *args, **kwargs):
        """See if we have a direct match. If so redirect, if not, search.

        Try fetching a remote profile if the search term is a handle or fid.
        """
        q = safe_text(request.GET.get("q"))
        if q:
            q = q.strip().lower()
        self.q = q
        # Check if direct tag matches
        if q.startswith('#'):
            try:
                tag = Tag.objects.filter(
                    name=q[1:]
                ).annotate(
                    content_count=Count('contents')
                ).filter(
                    content_count__gt=0
                ).get()
            except Tag.DoesNotExist:
                pass
            else:
                return redirect(tag.get_absolute_url())
        # Check if profile matches
        profile = None
        try:
            profile = Profile.objects.visible_for_user(request.user).fed(q).get()
        except Profile.DoesNotExist:
            # Try a remote search
            # TODO currently only if diaspora handle
            if validate_handle(q):
                try:
                    remote_profile = retrieve_remote_profile(q)
                except (AttributeError, ValueError, xml.parsers.expat.ExpatError):
                    # Catch various errors parsing the remote profile
                    return super().get(request, *args, **kwargs)
                if remote_profile:
                    profile = Profile.from_remote_profile(remote_profile)
        if profile:
            return redirect(reverse("users:profile-detail", kwargs={"uuid": profile.uuid}))
        try:
            return super().get(request, *args, **kwargs)
        except QueryError:
            # Re-render the form
            messages.warning(self.request, _("Search string is invalid, please try another one."))
            return HttpResponseRedirect(self.get_success_url())
Пример #18
0
def get_sender_profile(sender: str) -> Optional[Profile]:
    """Get or create sender profile.

    Fetch it from federation layer if necessary or if the public key is empty for some reason.
    """
    try:
        logger.debug("get_sender_profile - looking from local db using %s", sender)
        sender_profile = Profile.objects.fed(sender).exclude(rsa_public_key="").get()
    except Profile.DoesNotExist:
        logger.debug("get_sender_profile - %s was not found, fetching from remote", sender)
        remote_profile = retrieve_remote_profile(sender)
        if not remote_profile:
            logger.warning("get_sender_profile - Remote profile %s not found locally or remotely.", sender)
            return
        sender_profile = Profile.from_remote_profile(remote_profile)
    else:
        if sender_profile.is_local:
            logger.warning("get_sender_profile - %s is local! Skip.", sender)
            return
    return sender_profile