From 06ff249530ca644de6c7d479833dcf7ff9ef374f Mon Sep 17 00:00:00 2001 From: evazion Date: Fri, 23 Aug 2019 18:59:28 -0500 Subject: [PATCH] dmails: factor out spam detector service. --- app/controllers/dmails_controller.rb | 2 -- app/logical/spam_detector.rb | 44 ++++++++++++++++++++++++++++ app/models/dmail.rb | 8 +---- config/danbooru_default_config.rb | 1 + test/unit/dmail_test.rb | 7 ++--- test/unit/spam_detector.rb | 31 ++++++++++++++++++++ 6 files changed, 79 insertions(+), 14 deletions(-) create mode 100644 app/logical/spam_detector.rb create mode 100644 test/unit/spam_detector.rb diff --git a/app/controllers/dmails_controller.rb b/app/controllers/dmails_controller.rb index 4af7d3258..38b45ecae 100644 --- a/app/controllers/dmails_controller.rb +++ b/app/controllers/dmails_controller.rb @@ -58,13 +58,11 @@ class DmailsController < ApplicationController def spam @dmail = Dmail.find(params[:id]) @dmail.update_column(:is_spam, true) - @dmail.spam! end def ham @dmail = Dmail.find(params[:id]) @dmail.update_column(:is_spam, false) - @dmail.ham! end private diff --git a/app/logical/spam_detector.rb b/app/logical/spam_detector.rb new file mode 100644 index 000000000..6ef629503 --- /dev/null +++ b/app/logical/spam_detector.rb @@ -0,0 +1,44 @@ +# https://github.com/joshfrench/rakismet +# https://akismet.com/development/api/#comment-check + +class SpamDetector + include Rakismet::Model + + attr_accessor :user, :user_ip, :content, :comment_type + rakismet_attrs author: proc { user.name }, + author_email: proc { user.email }, + blog_lang: "en", + blog_charset: "UTF-8", + comment_type: :comment_type, + content: :content, + user_ip: :user_ip + + def self.enabled? + Danbooru.config.rakismet_key.present? && Danbooru.config.rakismet_url.present? && !Rails.env.test? + end + + # rakismet raises an exception if the api key or url aren't configured + def self.working? + Rakismet.validate_key + rescue + false + end + + def initialize(record) + case record + when Dmail + @user = record.from + @content = record.body + @comment_type = "message" + @user_ip = record.creator_ip_addr.to_s + else + raise ArgumentError + end + end + + def spam? + return false if !SpamDetector.enabled? + return false if user.is_gold? + super + end +end diff --git a/app/models/dmail.rb b/app/models/dmail.rb index b5934ef23..f5c0cdb17 100644 --- a/app/models/dmail.rb +++ b/app/models/dmail.rb @@ -6,8 +6,6 @@ class Dmail < ApplicationRecord AUTOBAN_WINDOW = 24.hours AUTOBAN_DURATION = 3 - include Rakismet::Model - validates_presence_of :title, :body, on: :create validate :validate_sender_is_not_banned, on: :create @@ -20,8 +18,6 @@ class Dmail < ApplicationRecord after_create :update_recipient after_commit :send_email, on: :create - rakismet_attrs author: proc { from.name }, author_email: proc { from.email }, content: proc { title + "\n\n" + body }, user_ip: proc { creator_ip_addr.to_s } - concerning :SpamMethods do class_methods do def is_spammer?(user) @@ -41,9 +37,7 @@ class Dmail < ApplicationRecord end def spam? - return false if Danbooru.config.rakismet_key.blank? - return false if from.is_gold? - super() + SpamDetector.new(self).spam? end end diff --git a/config/danbooru_default_config.rb b/config/danbooru_default_config.rb index 026ed3dfe..537e467b0 100644 --- a/config/danbooru_default_config.rb +++ b/config/danbooru_default_config.rb @@ -762,6 +762,7 @@ module Danbooru end def rakismet_url + "https://#{hostname}" end # Cloudflare data diff --git a/test/unit/dmail_test.rb b/test/unit/dmail_test.rb index a84277668..c6ed3ee8d 100644 --- a/test/unit/dmail_test.rb +++ b/test/unit/dmail_test.rb @@ -17,11 +17,8 @@ class DmailTest < ActiveSupport::TestCase context "spam" do setup do - Dmail.any_instance.stubs(:spam?).returns(true) unless Danbooru.config.rakismet_key.present? - - # viagra-test-123 is guaranteed to be flagged as spam. - # https://akismet.com/development/api/#detailed-docs - @spammer = create(:user, name: "viagra-test-123") + Dmail.any_instance.stubs(:spam?).returns(true) + @spammer = create(:user) @recipient = create(:user) end diff --git a/test/unit/spam_detector.rb b/test/unit/spam_detector.rb new file mode 100644 index 000000000..516c64c35 --- /dev/null +++ b/test/unit/spam_detector.rb @@ -0,0 +1,31 @@ +require "test_helper" + +class SpamDetectorTest < ActiveSupport::TestCase + context "SpamDetector" do + setup do + skip "SpamDetector not working: API key not configured, not valid, or akismet is down" if !SpamDetector.working? + SpamDetector.stubs(:enabled?).returns(true) + + @user = create(:gold_user) + @spammer = create(:user, email: "akismet-guaranteed-spam@example.com") + end + + context "for dmails" do + should "detect spam" do + Dmail.create_split(from: @spammer, to: @user, title: "spam", body: "wonderful spam", creator_ip_addr: "127.0.0.1") + + dmail = @user.dmails.last + assert(SpamDetector.new(dmail).spam?) + assert(dmail.is_spam?) + end + + should "not detect gold users as spammers" do + Dmail.create_split(from: @user, to: @spammer, title: "spam", body: "wonderful spam", creator_ip_addr: "127.0.0.1") + + dmail = @spammer.dmails.last + refute(SpamDetector.new(dmail).spam?) + refute(dmail.is_spam?) + end + end + end +end