dmails: factor out spam detector service.
This commit is contained in:
@@ -58,13 +58,11 @@ class DmailsController < ApplicationController
|
|||||||
def spam
|
def spam
|
||||||
@dmail = Dmail.find(params[:id])
|
@dmail = Dmail.find(params[:id])
|
||||||
@dmail.update_column(:is_spam, true)
|
@dmail.update_column(:is_spam, true)
|
||||||
@dmail.spam!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def ham
|
def ham
|
||||||
@dmail = Dmail.find(params[:id])
|
@dmail = Dmail.find(params[:id])
|
||||||
@dmail.update_column(:is_spam, false)
|
@dmail.update_column(:is_spam, false)
|
||||||
@dmail.ham!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
44
app/logical/spam_detector.rb
Normal file
44
app/logical/spam_detector.rb
Normal file
@@ -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
|
||||||
@@ -6,8 +6,6 @@ class Dmail < ApplicationRecord
|
|||||||
AUTOBAN_WINDOW = 24.hours
|
AUTOBAN_WINDOW = 24.hours
|
||||||
AUTOBAN_DURATION = 3
|
AUTOBAN_DURATION = 3
|
||||||
|
|
||||||
include Rakismet::Model
|
|
||||||
|
|
||||||
validates_presence_of :title, :body, on: :create
|
validates_presence_of :title, :body, on: :create
|
||||||
validate :validate_sender_is_not_banned, on: :create
|
validate :validate_sender_is_not_banned, on: :create
|
||||||
|
|
||||||
@@ -20,8 +18,6 @@ class Dmail < ApplicationRecord
|
|||||||
after_create :update_recipient
|
after_create :update_recipient
|
||||||
after_commit :send_email, on: :create
|
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
|
concerning :SpamMethods do
|
||||||
class_methods do
|
class_methods do
|
||||||
def is_spammer?(user)
|
def is_spammer?(user)
|
||||||
@@ -41,9 +37,7 @@ class Dmail < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def spam?
|
def spam?
|
||||||
return false if Danbooru.config.rakismet_key.blank?
|
SpamDetector.new(self).spam?
|
||||||
return false if from.is_gold?
|
|
||||||
super()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -762,6 +762,7 @@ module Danbooru
|
|||||||
end
|
end
|
||||||
|
|
||||||
def rakismet_url
|
def rakismet_url
|
||||||
|
"https://#{hostname}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Cloudflare data
|
# Cloudflare data
|
||||||
|
|||||||
@@ -17,11 +17,8 @@ class DmailTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
context "spam" do
|
context "spam" do
|
||||||
setup do
|
setup do
|
||||||
Dmail.any_instance.stubs(:spam?).returns(true) unless Danbooru.config.rakismet_key.present?
|
Dmail.any_instance.stubs(:spam?).returns(true)
|
||||||
|
@spammer = create(:user)
|
||||||
# viagra-test-123 is guaranteed to be flagged as spam.
|
|
||||||
# https://akismet.com/development/api/#detailed-docs
|
|
||||||
@spammer = create(:user, name: "viagra-test-123")
|
|
||||||
@recipient = create(:user)
|
@recipient = create(:user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
31
test/unit/spam_detector.rb
Normal file
31
test/unit/spam_detector.rb
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user