From 002b5e385a3543e18bb7b8d2b4d615444b8a0c4d Mon Sep 17 00:00:00 2001 From: evazion Date: Fri, 15 Dec 2017 15:55:27 -0600 Subject: [PATCH] Autoban dmail spambots (#3408). If a user sends spam to more than 10 users within a 24 hour window, automatically ban them for 3 days. --- app/models/dmail.rb | 28 ++++++++++++++++++++++++++++ test/unit/dmail_test.rb | 15 +++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/app/models/dmail.rb b/app/models/dmail.rb index da4344a3e..0bfcb7eb0 100644 --- a/app/models/dmail.rb +++ b/app/models/dmail.rb @@ -1,6 +1,11 @@ require 'digest/sha1' class Dmail < ApplicationRecord + # if a person sends spam to more than 10 users within a 24 hour window, automatically ban them for 3 days. + AUTOBAN_THRESHOLD = 10 + AUTOBAN_WINDOW = 24.hours + AUTOBAN_DURATION = 3 + include Rakismet::Model with_options on: :create do @@ -23,6 +28,23 @@ class Dmail < ApplicationRecord rakismet_attrs author: :from_name, author_email: :from_email, content: :title_and_body, user_ip: :creator_ip_addr_str concerning :SpamMethods do + class_methods do + def is_spammer?(user) + return false if user.is_gold? + + spammed_users = sent_by(user).where(is_spam: true).where("created_at > ?", AUTOBAN_WINDOW.ago).distinct.count(:to_id) + spammed_users >= AUTOBAN_THRESHOLD + end + + def ban_spammer(spammer) + spammer.bans.create! do |ban| + ban.banner = User.system + ban.reason = "Spambot." + ban.duration = AUTOBAN_DURATION + end + end + end + def title_and_body "#{title}\n\n#{body}" end @@ -80,6 +102,8 @@ class Dmail < ApplicationRecord copy.owner_id = copy.from_id copy.is_read = true copy.save + + Dmail.ban_spammer(copy.from) if Dmail.is_spammer?(copy.from) end copy @@ -119,6 +143,10 @@ class Dmail < ApplicationRecord end module SearchMethods + def sent_by(user) + where("dmails.from_id = ? AND dmails.owner_id != ?", user.id, user.id) + end + def active where("is_deleted = ?", false) end diff --git a/test/unit/dmail_test.rb b/test/unit/dmail_test.rb index 875eaedb8..7e40ffcd9 100644 --- a/test/unit/dmail_test.rb +++ b/test/unit/dmail_test.rb @@ -3,6 +3,7 @@ require 'test_helper' class DmailTest < ActiveSupport::TestCase context "A dmail" do setup do + User.any_instance.stubs(:validate_sock_puppets).returns(true) @user = FactoryGirl.create(:user) CurrentUser.user = @user CurrentUser.ip_addr = "1.2.3.4" @@ -27,6 +28,20 @@ class DmailTest < ActiveSupport::TestCase assert(@recipient.dmails.last.is_spam?) end end + + should "autoban spammers after sending spam to N distinct users" do + Dmail.any_instance.expects(:spam?).returns(true) + + users = FactoryGirl.create_list(:user, Dmail::AUTOBAN_THRESHOLD) + users.each do |user| + Dmail.create_split(from: @user, to: user, title: "spam", body: "wonderful spam") + end + + assert_equal(true, Dmail.is_spammer?(@user)) + assert_equal(true, @user.reload.is_banned) + assert_equal(1, @user.bans.count) + assert_match(/Spambot./, @user.bans.last.reason) + end end context "filter" do