about summary refs log tree commit diff
path: root/app/services
diff options
context:
space:
mode:
authormultiple creatures <dev@multiple-creature.party>2019-08-08 09:59:14 -0500
committermultiple creatures <dev@multiple-creature.party>2019-08-08 12:46:17 -0500
commit4dfc40324b1f3b20550982621501e162d2ed3bed (patch)
tree1578cba8809b7db27dc82f4d439471194d5fad31 /app/services
parentd019e55b7bc496d3c4d942fb4ffe65bb7e149249 (diff)
add new `reject unknown` policy option to prevent spam & harassment from large/undermoderated servers
Diffstat (limited to 'app/services')
-rw-r--r--app/services/activitypub/fetch_remote_status_service.rb4
-rw-r--r--app/services/block_domain_service.rb51
-rw-r--r--app/services/favourite_service.rb2
-rw-r--r--app/services/fetch_remote_status_service.rb5
-rw-r--r--app/services/follow_service.rb2
-rw-r--r--app/services/post_status_service.rb5
-rw-r--r--app/services/reblog_service.rb2
-rw-r--r--app/services/resolve_url_service.rb2
8 files changed, 59 insertions, 14 deletions
diff --git a/app/services/activitypub/fetch_remote_status_service.rb b/app/services/activitypub/fetch_remote_status_service.rb
index 42280ad74..423c7bc9a 100644
--- a/app/services/activitypub/fetch_remote_status_service.rb
+++ b/app/services/activitypub/fetch_remote_status_service.rb
@@ -5,7 +5,7 @@ class ActivityPub::FetchRemoteStatusService < BaseService
   include AutorejectHelper
 
   # Should be called when uri has already been checked for locality
-  def call(uri, id: true, prefetched_body: nil, on_behalf_of: nil)
+  def call(uri, id: true, prefetched_body: nil, on_behalf_of: nil, announced_by: nil, requested: false)
     return if autoreject?(uri)
 
     @json = if prefetched_body.nil?
@@ -24,7 +24,7 @@ class ActivityPub::FetchRemoteStatusService < BaseService
 
     return if actor.nil? || actor.suspended?
 
-    ActivityPub::Activity.factory(activity_json, actor).perform
+    ActivityPub::Activity.factory(activity_json, actor, announced_by: announced_by, requested: requested).perform
   end
 
   private
diff --git a/app/services/block_domain_service.rb b/app/services/block_domain_service.rb
index 908deacf4..5a6f4a6ce 100644
--- a/app/services/block_domain_service.rb
+++ b/app/services/block_domain_service.rb
@@ -5,8 +5,11 @@ class BlockDomainService < BaseService
 
   def call(domain_block)
     @domain_block = domain_block
+    @affected_status_ids = []
+
     remove_existing_block!
     process_domain_block!
+    invalidate_association_caches!
   end
 
   private
@@ -16,8 +19,9 @@ class BlockDomainService < BaseService
   end
 
   def process_domain_block!
-    clear_media! if domain_block.reject_media?
+    clear_media! if domain_block.reject_media? || domain_block.suspend?
     force_accounts_sensitive! if domain_block.force_sensitive?
+    mark_unknown_accounts! if domain_block.reject_unknown?
 
     if domain_block.force_unlisted?
       force_accounts_unlisted!
@@ -39,17 +43,22 @@ class BlockDomainService < BaseService
   def force_accounts_sensitive!
     ApplicationRecord.transaction do
       blocked_domain_accounts.in_batches.update_all(force_sensitive: true)
-      blocked_domain_accounts.reorder(nil).find_each do |account|
+      blocked_domain_accounts.find_each do |account|
+        @affected_status_ids |= account.statuses.where(sensitive: false).pluck(:id)
         account.statuses.where(sensitive: false).in_batches.update_all(sensitive: true)
       end
     end
-    invalidate_association_caches! unless @affected_status_ids.blank?
+  end
+
+  def mark_unknown_accounts!
+    unknown_accounts.in_batches.update_all(known: false)
   end
 
   def force_accounts_unlisted!
     ApplicationRecord.transaction do
       blocked_domain_accounts.in_batches.update_all(force_unlisted: true)
-      blocked_domain_accounts.reorder(nil).find_each do |account|
+      blocked_domain_accounts.find_each do |account|
+        @affected_status_ids |= account.statuses.with_public_visibility.pluck(:id)
         account.statuses.with_public_visibility.in_batches.update_all(visibility: :unlisted)
       end
     end
@@ -60,23 +69,21 @@ class BlockDomainService < BaseService
   end
 
   def clear_media!
-    @affected_status_ids = []
 
     clear_account_images!
     clear_account_attachments!
     clear_emojos!
 
-    invalidate_association_caches!
   end
 
   def suspend_accounts!
-    blocked_domain_accounts.without_suspended.reorder(nil).find_each do |account|
+    blocked_domain_accounts.without_suspended.find_each do |account|
       SuspendAccountService.new.call(account, suspended_at: @domain_block.created_at)
     end
   end
 
   def clear_account_images!
-    blocked_domain_accounts.reorder(nil).find_each do |account|
+    blocked_domain_accounts.find_each do |account|
       account.avatar.destroy if account.avatar.exists?
       account.header.destroy if account.header.exists?
       account.save
@@ -84,7 +91,7 @@ class BlockDomainService < BaseService
   end
 
   def clear_account_attachments!
-    media_from_blocked_domain.reorder(nil).find_each do |attachment|
+    media_from_blocked_domain.find_each do |attachment|
       @affected_status_ids << attachment.status_id if attachment.status_id.present?
 
       attachment.file.destroy if attachment.file.exists?
@@ -102,7 +109,7 @@ class BlockDomainService < BaseService
   end
 
   def blocked_domain_accounts
-    Account.where(domain: blocked_domain)
+    Account.where(domain: blocked_domain).reorder(nil)
   end
 
   def media_from_blocked_domain
@@ -112,4 +119,28 @@ class BlockDomainService < BaseService
   def emojis_from_blocked_domains
     CustomEmoji.where(domain: blocked_domain)
   end
+
+  def unknown_accounts
+    Account.where(id: blocked_domain_accounts.pluck(:id) - known_account_ids).reorder(nil)
+  end
+
+  def known_account_ids
+    local_accounts | packmates | boosted_authors | faved_authors
+  end
+
+  def boosted_authors
+    Status.where(id: Status.local.reblogs.reorder(nil).select(:reblog_of_id)).reorder(nil).pluck(:account_id)
+  end
+
+  def faved_authors
+    Status.where(id: Favourite.select(:status_id)).reorder(nil).pluck(:account_id)
+  end
+
+  def local_accounts
+    Account.local.pluck(:id)
+  end
+
+  def packmates
+    Account.local.flat_map { |account| account.following_ids | account.follower_ids }
+  end
 end
diff --git a/app/services/favourite_service.rb b/app/services/favourite_service.rb
index ee3248877..ce13b92ed 100644
--- a/app/services/favourite_service.rb
+++ b/app/services/favourite_service.rb
@@ -16,6 +16,8 @@ class FavouriteService < BaseService
 
     favourite = Favourite.create!(account: account, status: status)
 
+    status.account.mark_known! unless status.account.known?
+
     curate_status(status)
     create_notification(favourite) unless skip_notify
     bump_potential_friendship(account, status)
diff --git a/app/services/fetch_remote_status_service.rb b/app/services/fetch_remote_status_service.rb
index 2c6dbb58d..4fde2b395 100644
--- a/app/services/fetch_remote_status_service.rb
+++ b/app/services/fetch_remote_status_service.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class FetchRemoteStatusService < BaseService
-  def call(url, prefetched_body = nil)
+  def call(url, prefetched_body = nil, announced_by: nil, requested: false)
     if prefetched_body.nil?
       resource_url, resource_options = FetchAtomService.new.call(url)
     else
@@ -9,6 +9,9 @@ class FetchRemoteStatusService < BaseService
       resource_options = { prefetched_body: prefetched_body }
     end
 
+    resource_options[:announced_by] = announced_by unless announced_by.nil?
+    resource_options[:requested] = true if requested
+
     return if resource_url.blank?
     ActivityPub::FetchRemoteStatusService.new.call(resource_url, **resource_options)
   end
diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb
index 3494dce99..776c4cb9b 100644
--- a/app/services/follow_service.rb
+++ b/app/services/follow_service.rb
@@ -14,6 +14,8 @@ class FollowService < BaseService
     raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended?
     raise Mastodon::NotPermittedError  if target_account.blocking?(source_account) || source_account.blocking?(target_account) || target_account.moved?
 
+    target_account.mark_known! unless target_account.known?
+
     if source_account.following?(target_account)
       # We're already following this account, but we'll call follow! again to
       # make sure the reblogs status is set correctly.
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index bd076eaf4..6377248e5 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -94,6 +94,10 @@ class PostStatusService < BaseService
     @in_reply_to.present? && @in_reply_to.reject_replies && @in_reply_to.account_id != @account.id
   end
 
+  def mark_recipient_known
+    @in_reply_to.account.mark_known! unless @in_reply_to.account.known?
+  end
+
   def set_footer_from_i_am
     return if @footer.present? || @options[:no_footer]
     name = @account.user.vars['_they:are']
@@ -153,6 +157,7 @@ class PostStatusService < BaseService
     limit_visibility_if_silenced
 
     unless @in_reply_to.nil?
+      mark_recipient_known
       inherit_reply_rejection
       limit_visibility_to_reply
       unfilter_thread_on_reply
diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb
index 7d72357f9..1e7d4f3ca 100644
--- a/app/services/reblog_service.rb
+++ b/app/services/reblog_service.rb
@@ -17,6 +17,8 @@ class ReblogService < BaseService
     new_reblog = reblog.nil?
 
     if new_reblog
+      reblogged_status.account.mark_known! unless reblogged_status.account.known?
+
       visibility = options[:visibility] || account.user&.setting_default_privacy
       visibility = reblogged_status.visibility if reblogged_status.hidden?
       reblog = account.statuses.create!(reblog: reblogged_status, text: '', visibility: visibility)
diff --git a/app/services/resolve_url_service.rb b/app/services/resolve_url_service.rb
index 89a31c9ed..0c265b0db 100644
--- a/app/services/resolve_url_service.rb
+++ b/app/services/resolve_url_service.rb
@@ -21,7 +21,7 @@ class ResolveURLService < BaseService
     if equals_or_includes_any?(type, %w(Application Group Organization Person Service))
       FetchRemoteAccountService.new.call(atom_url, body)
     elsif equals_or_includes_any?(type, %w(Note Article Image Video Page Question))
-      FetchRemoteStatusService.new.call(atom_url, body)
+      FetchRemoteStatusService.new.call(atom_url, body, requested: true)
     end
   end