Use an event for the spam check in message forms
authorMarcel Werk <burntime@woltlab.com>
Thu, 30 May 2024 16:29:04 +0000 (18:29 +0200)
committerMarcel Werk <burntime@woltlab.com>
Thu, 30 May 2024 16:29:04 +0000 (18:29 +0200)
wcfsetup/install/files/lib/bootstrap/com.woltlab.wcf.php
wcfsetup/install/files/lib/event/message/MessageSpamChecking.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/form/MessageForm.class.php
wcfsetup/install/files/lib/system/event/listener/MessageSpamCheckingSfsListener.class.php [new file with mode: 0644]

index 6f51b916cd57de3bca74b90bf0a97055d5c4235b..722d25b6bf52549e4f7cda14d7d4eea7237fa42c 100644 (file)
@@ -41,6 +41,10 @@ return static function (): void {
         \wcf\event\page\ContactFormSpamChecking::class,
         \wcf\system\event\listener\ContactFormSpamCheckingSfsListener::class
     );
+    $eventHandler->register(
+        \wcf\event\message\MessageSpamChecking::class,
+        \wcf\system\event\listener\MessageSpamCheckingSfsListener::class
+    );
 
     $eventHandler->register(
         \wcf\event\package\PackageListChanged::class,
diff --git a/wcfsetup/install/files/lib/event/message/MessageSpamChecking.class.php b/wcfsetup/install/files/lib/event/message/MessageSpamChecking.class.php
new file mode 100644 (file)
index 0000000..82effb2
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+namespace wcf\event\message;
+
+use wcf\data\user\User;
+use wcf\event\IInterruptableEvent;
+use wcf\event\TInterruptableEvent;
+use wcf\system\html\input\HtmlInputProcessor;
+
+/**
+ * Indicates that a new message by a user is currently validated. If this event is interrupted,
+ * the message is considered to be spam.
+ *
+ * @author      Marcel Werk
+ * @copyright   2001-2024 WoltLab GmbH
+ * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @since       6.1
+ */
+final class MessageSpamChecking implements IInterruptableEvent
+{
+    use TInterruptableEvent;
+
+    public function __construct(
+        public readonly HtmlInputProcessor $processor,
+        public readonly ?User $user = null,
+        public readonly string $ipAddress = '',
+        public readonly string $subject = '',
+    ) {
+    }
+}
index 6ef0400cf5817b69f346a1f5ddc24a2565b84ff4..332da7da8f01df3f1b4bb56ec4e0ed7caeaf3a76 100644 (file)
@@ -6,8 +6,10 @@ use wcf\data\language\Language;
 use wcf\data\smiley\category\SmileyCategory;
 use wcf\data\smiley\Smiley;
 use wcf\data\smiley\SmileyCache;
+use wcf\event\message\MessageSpamChecking;
 use wcf\system\attachment\AttachmentHandler;
 use wcf\system\bbcode\BBCodeHandler;
+use wcf\system\event\EventHandler;
 use wcf\system\exception\UserInputException;
 use wcf\system\html\input\HtmlInputProcessor;
 use wcf\system\html\upcast\HtmlUpcastProcessor;
@@ -16,6 +18,7 @@ use wcf\system\message\censorship\Censorship;
 use wcf\system\WCF;
 use wcf\util\MessageUtil;
 use wcf\util\StringUtil;
+use wcf\util\UserUtil;
 
 /**
  * MessageForm is an abstract form implementation for a message with optional captcha support.
@@ -347,4 +350,22 @@ abstract class MessageForm extends AbstractCaptchaForm
             'tmpHash' => $this->tmpHash,
         ]);
     }
+
+    /**
+     * This method triggers the event for the spam check and returns the result.
+     *
+     * @since 6.1
+     */
+    protected function messageIsProbablySpam(): bool
+    {
+        $event = new MessageSpamChecking(
+            $this->htmlInputProcessor,
+            WCF::getUser()->userID ? WCF::getUser() : null,
+            UserUtil::getIpAddress(),
+            $this->subject,
+        );
+        EventHandler::getInstance()->fire($event);
+
+        return $event->defaultPrevented();
+    }
 }
diff --git a/wcfsetup/install/files/lib/system/event/listener/MessageSpamCheckingSfsListener.class.php b/wcfsetup/install/files/lib/system/event/listener/MessageSpamCheckingSfsListener.class.php
new file mode 100644 (file)
index 0000000..3b51d82
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+
+namespace wcf\system\event\listener;
+
+use wcf\data\blacklist\entry\BlacklistEntry;
+use wcf\event\message\MessageSpamChecking;
+use wcf\system\cache\runtime\UserProfileRuntimeCache;
+
+/**
+ * Checks for spam messages using data from Stop Forum Spam.
+ *
+ * @author      Marcel Werk
+ * @copyright   2001-2024 WoltLab GmbH
+ * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @since       6.1
+ */
+final class MessageSpamCheckingSfsListener
+{
+    public function __invoke(MessageSpamChecking $event): void
+    {
+        if (!\BLACKLIST_SFS_ENABLE) {
+            return;
+        }
+
+        if ($event->user !== null) {
+            // Skip spam check for admins and moderators
+            $userProfile = UserProfileRuntimeCache::getInstance()->getObject($event->user->userID);
+            if (
+                $userProfile->getPermission('admin.general.canUseAcp')
+                || $userProfile->getPermission('mod.general.canUseModeration')
+            ) {
+                return;
+            }
+        }
+
+        if (BlacklistEntry::getMatches(
+            $event->user ? $event->user->username : '',
+            $event->user ? $event->user->email : '',
+            $event->ipAddress,
+        ) !== []) {
+            $event->preventDefault();
+        }
+    }
+}