dmails: factor out spam detector service.

This commit is contained in:
evazion 2019-08-23 18:59:28 -05:00 committed by Kira
parent 84e8eb1bc8
commit 30ee20a570
6 changed files with 80 additions and 11 deletions

View File

@ -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

View 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

View File

@ -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
validate :user_not_limited, on: :create
@ -21,8 +19,6 @@ class Dmail < ApplicationRecord
after_create :update_recipient
after_commit :send_email, on: :create
rakismet_attrs author: -> { from.name }, author_email: -> { from.email }, content: -> { title + "\n\n" + body }, user_ip: -> { creator_ip_addr.to_s }
concerning :SpamMethods do
class_methods do
def is_spammer?(user)
@ -42,9 +38,7 @@ class Dmail < ApplicationRecord
end
def spam?
return false if Danbooru.config.rakismet_key.blank?
return false if from.is_janitor?
super()
SpamDetector.new(self).spam?
end
end
@ -253,7 +247,7 @@ class Dmail < ApplicationRecord
to.update(has_mail: true, unread_dmail_count: to.dmails.unread.count)
end
end
def visible_to?(user)
owner_id == user.id || (user.is_admin? && (to.is_admin? || from.is_admin? || Ticket.exists?(qtype: 'dmail', disp_id: id)))
end

View File

@ -845,6 +845,7 @@ module Danbooru
end
def rakismet_url
"https://#{hostname}"
end
# Cloudflare data

View File

@ -18,7 +18,8 @@ class DmailTest < ActiveSupport::TestCase
context "spam" do
setup do
Dmail.any_instance.stubs(:spam?).returns(true)
@recipient = FactoryBot.create(:user)
@spammer = create(:user)
@recipient = create(:user)
end
should "not validate" do

View 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