From 99f36f1b7b4350747de5043eed2528291aa4c469 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 22 Nov 2024 15:43:16 +0100
Subject: [PATCH] Tweak antispam a bit (#33024)

---
 app/lib/antispam.rb | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/app/lib/antispam.rb b/app/lib/antispam.rb
index bc4841280..4ebf19248 100644
--- a/app/lib/antispam.rb
+++ b/app/lib/antispam.rb
@@ -5,25 +5,36 @@ class Antispam
 
   ACCOUNT_AGE_EXEMPTION = 1.week.freeze
 
+  class DummyStatus < SimpleDelegator
+    def self.model_name
+      Mention.model_name
+    end
+
+    def active_mentions
+      # Don't use the scope but the in-memory array
+      mentions.filter { |mention| !mention.silent? }
+    end
+  end
+
   class SilentlyDrop < StandardError
     attr_reader :status
 
     def initialize(status)
       super()
 
-      @status = status
-
       status.created_at = Time.now.utc
       status.id = Mastodon::Snowflake.id_at(status.created_at)
       status.in_reply_to_account_id = status.thread&.account_id
 
       status.delete # Make sure this is not persisted
+
+      @status = DummyStatus.new(status)
     end
   end
 
   def local_preflight_check!(status)
     return unless spammy_texts.any? { |spammy_text| status.text.include?(spammy_text) }
-    return unless status.thread.present? && !status.thread.account.following?(status.account)
+    return unless suspicious_reply_or_mention?(status)
     return unless status.account.created_at >= ACCOUNT_AGE_EXEMPTION.ago
 
     report_if_needed!(status.account)
@@ -37,6 +48,14 @@ class Antispam
     redis.smembers('antispam:spammy_texts')
   end
 
+  def suspicious_reply_or_mention?(status)
+    parent = status.thread
+    return true if parent.present? && !Follow.exists?(account_id: parent.account_id, target_account: status.account_id)
+
+    account_ids = status.mentions.map(&:account_id).uniq
+    !Follow.exists?(account_id: account_ids, target_account_id: status.account.id)
+  end
+
   def report_if_needed!(account)
     return if Report.unresolved.exists?(account: Account.representative, target_account: account)