def send_profile(profile_id, recipients=None): """Handle sending a Profile object out via the federation layer. :param profile_id: Profile.id of profile to send :param recipients: Optional list of recipients, see `federation.outbound.handle_send` parameters """ try: profile = Profile.objects.get(id=profile_id, user__isnull=False) except Profile.DoesNotExist: logger.warning("send_profile - No local profile found with id %s", profile_id) return entity = make_federable_profile(profile) if not entity: logger.warning("send_profile - No entity for %s", profile) return if settings.DEBUG: # Don't send in development mode return if not recipients: # If we have Matrix support enabled, also add the appservice if settings.SOCIALHOME_MATRIX_ENABLED: recipients = [profile.get_recipient_for_matrix_appservice()] else: recipients = [] recipients.extend(_get_remote_followers(profile, profile.visibility)) logger.debug("send_profile - sending to recipients: %s", recipients) handle_send(entity, profile.federable, recipients, payload_logger=get_outbound_payload_logger())
def send_profile_retraction(profile): """Handle sending of retractions for profiles. Only sent for public and limited profiles. Reason: we might actually leak user information outside for profiles which were never federated outside if we send for example SELF or SITE profile retractions. This must be called as a pre_delete signal or it will fail. """ if profile.visibility not in (Visibility.PUBLIC, Visibility.LIMITED) or not profile.is_local: return entity = make_federable_retraction(profile) if entity: if settings.DEBUG: # Don't send in development mode return recipients = _get_remote_followers(profile, profile.visibility) logger.debug("send_profile_retraction - sending to recipients: %s", recipients) handle_send(entity, profile.federable, recipients, payload_logger=get_outbound_payload_logger()) else: logger.warning("send_profile_retraction - No retraction entity for %s", profile)
def send_share(content_id, activity_fid): """Handle sending a share of a Content object to the federation layer. Currently we only deliver public shares. """ try: content = Content.objects.get(id=content_id, visibility=Visibility.PUBLIC, content_type=ContentType.SHARE, local=True) except Content.DoesNotExist: logger.warning("No local share found with id %s", content_id) return entity = make_federable_content(content) if entity: entity.activity_id = activity_fid if settings.DEBUG: # Don't send in development mode return recipients = _get_remote_followers(content.author, content.visibility) if not content.share_of.local: # Send to original author recipients.append( content.share_of.author.get_recipient_for_visibility( content.visibility)) logger.debug("send_share - sending to recipients: %s", recipients) handle_send(entity, content.author.federable, recipients, payload_logger=get_outbound_payload_logger()) else: logger.warning("send_share - No entity for %s", content)
def send_profile(profile_id, recipients=None): """Handle sending a Profile object out via the federation layer. :param profile_id: Profile.id of profile to send :param recipients: Optional list of recipients, see `federation.outbound.handle_send` parameters """ try: profile = Profile.objects.get(id=profile_id, user__isnull=False) except Profile.DoesNotExist: logger.warning("send_profile - No local profile found with id %s", profile_id) return entity = make_federable_profile(profile) if not entity: logger.warning("send_profile - No entity for %s", profile) return if settings.DEBUG: # Don't send in development mode return if not recipients: recipients = _get_remote_followers(profile, profile.visibility) logger.debug("send_profile - sending to recipients: %s", recipients) handle_send(entity, profile.federable, recipients, payload_logger=get_outbound_payload_logger())
def send_content(content_id, activity_fid, recipient_id=None): """ Handle sending a Content object out via the federation layer. """ try: content = Content.objects.get( id=content_id, visibility__in=(Visibility.PUBLIC, Visibility.LIMITED), content_type=ContentType.CONTENT, local=True, ) except Content.DoesNotExist: logger.warning("No local content found with id %s", content_id) return if recipient_id: try: recipient = Profile.objects.get(id=recipient_id, user__isnull=True) except Profile.DoesNotExist: logger.warning("No remote recipient found with id %s", recipient_id) return else: recipient = None entity = make_federable_content(content) if entity: entity.activity_id = activity_fid if settings.DEBUG: # Don't send in development mode return recipients = [] if recipient: recipients.append( recipient.get_recipient_for_visibility(content.visibility)) else: if content.visibility == Visibility.PUBLIC: # If we have Matrix support enabled, also add the appservice if settings.SOCIALHOME_MATRIX_ENABLED: recipients.append( content.author.get_recipient_for_matrix_appservice()) if settings.SOCIALHOME_RELAY_ID: recipients.append({ "endpoint": settings.SOCIALHOME_RELAY_ID, "fid": "", "public": True, "protocol": "diaspora" }) recipients.extend( _get_remote_followers(content.author, content.visibility)) logger.debug("send_content - sending to recipients: %s", recipients) handle_send(entity, content.author.federable, recipients, payload_logger=get_outbound_payload_logger()) else: logger.warning("send_content - No entity for %s", content)
def send_reply(content_id, activity_fid): """ Handle sending a Content object that is a reply out via the federation layer. """ try: content = Content.objects.get( id=content_id, visibility__in=(Visibility.PUBLIC, Visibility.LIMITED), content_type=ContentType.REPLY, local=True, ) except Content.DoesNotExist: logger.warning("No content found with id %s", content_id) return entity = make_federable_content(content) if not entity: logger.warning("send_reply - No entity for %s", content) entity.activity_id = activity_fid if settings.DEBUG: # Don't send in development mode return recipients = [] if not content.root_parent.author.is_local: recipients.append( content.root_parent.author.get_recipient_for_visibility( content.visibility)) if content.visibility == Visibility.PUBLIC: recipients.extend( _get_remote_participants_for_content(content, exclude=content.author.fid, include_remote=True), ) recipients.extend( _get_remote_followers( content.author, content.visibility, exclude=content.author.fid, )) elif content.visibility == Visibility.LIMITED: recipients.extend(_get_limited_recipients(content.author.fid, content)) else: return if not recipients: logger.debug("send_reply - no remote recipients for content: %s", content.id) return logger.debug("send_reply - sending to recipients: %s", recipients) handle_send(entity, content.author.federable, recipients, payload_logger=get_outbound_payload_logger())
def forward_entity(entity, target_content_id): """Handle forwarding of an entity related to a target content. For example: remote replies on local content, remote shares on local content. """ try: target_content = Content.objects.get( id=target_content_id, visibility__in=(Visibility.PUBLIC, Visibility.LIMITED), local=True, ) except Content.DoesNotExist: logger.warning("forward_entity - No local content found with id %s", target_content_id) return try: content = Content.objects.fed( entity.id, visibility__in=(Visibility.PUBLIC, Visibility.LIMITED)).get() except Content.DoesNotExist: logger.warning("forward_entity - No content found with uuid %s", entity.id) return if settings.DEBUG: # Don't send in development mode return if target_content.visibility == Visibility.PUBLIC: recipients = _get_remote_participants_for_content( target_content, exclude=entity.actor_id) recipients.extend( _get_remote_followers( target_content.author, target_content.visibility, exclude=entity.actor_id, )) elif target_content.visibility == Visibility.LIMITED and content.content_type == ContentType.REPLY: recipients = _get_limited_recipients(entity.actor_id, target_content) else: return logger.debug("forward_entity - sending to recipients: %s", recipients) handle_send( entity, content.author.federable, recipients, parent_user=target_content.author.federable, payload_logger=get_outbound_payload_logger(), )
def send_content_retraction(content, author_id): """ Handle sending of retractions for content. """ if content.visibility not in (Visibility.PUBLIC, Visibility.LIMITED) or not content.local: return author = Profile.objects.get(id=author_id) entity = make_federable_retraction(content, author) if entity: if settings.DEBUG: # Don't send in development mode return if content.visibility == Visibility.PUBLIC: recipients = [] if settings.SOCIALHOME_RELAY_ID: recipients.append({ "endpoint": settings.SOCIALHOME_RELAY_ID, "fid": "", "public": True, "protocol": "diaspora" }) recipients.extend(_get_remote_followers(author, content.visibility)) else: recipients = _get_limited_recipients(author.fid, content) logger.debug("send_content_retraction - sending to recipients: %s", recipients) # Queue to the background since sending could take a while django_rq.enqueue( handle_send, entity, author.federable, recipients, payload_logger=get_outbound_payload_logger(), job_timeout=10000, ) else: logger.warning("send_content_retraction - No retraction entity for %s", content)
def send_follow_change(profile_id, followed_id, follow): """Handle sending of a local follow of a remote profile.""" try: profile = Profile.objects.get(id=profile_id, user__isnull=False) except Profile.DoesNotExist: logger.warning( "send_follow_change - No local profile %s found to send follow with", profile_id) return try: remote_profile = Profile.objects.get(id=followed_id, user__isnull=True) except Profile.DoesNotExist: logger.warning( "send_follow_change - No remote profile %s found to send follow for", followed_id) return if settings.DEBUG: # Don't send in development mode return entity = base.Follow( activity_id=f'{profile.fid}#follow-{uuid4()}', actor_id=profile.fid, target_id=remote_profile.fid, following=follow, handle=profile.handle, target_handle=remote_profile.handle, ) # Explicitly use limited visibility to force private endpoint recipients = [ remote_profile.get_recipient_for_visibility(Visibility.LIMITED) ] logger.debug("send_follow_change - sending to recipients: %s", recipients) handle_send(entity, profile.federable, recipients, payload_logger=get_outbound_payload_logger()) # Also trigger a profile send send_profile(profile_id, recipients=recipients)