Skip to content

Commit

Permalink
fresh approach to spam protection with a filter_chain to make things …
Browse files Browse the repository at this point in the history
…more flexible
  • Loading branch information
Sven Fuchs committed Jul 13, 2008
1 parent 6a13da0 commit 391423f
Show file tree
Hide file tree
Showing 34 changed files with 565 additions and 335 deletions.
59 changes: 57 additions & 2 deletions TODO
Expand Up @@ -3,8 +3,6 @@ This is just a collection of ideas, notes, ressource and less important stuff.
Please refer to the issue tracker at
http://artweb-design.lighthouseapp.com/projects/13992-adva_cms/overview

francois@teksol.info


[theme] separate login and admin/login pages (same thing, different layout) ?
[feature] admin section: have an activity center/dashboard where engines can register their
Expand Down Expand Up @@ -213,6 +211,63 @@ check fleximage http://github.com/Squeegy/fleximage/tree/master
check http://github.com/walf443/classx/tree/master
check http://github.com/tokumine/awesome_nested_set/tree/master



# Spam protection

Users should be able to add and configure custom spam filters easily.
Users should be able to configure the applications response to spam filter
results flexibly.

Spam filters can be registered to the application (e.g. from a plugin). There
are built-in spam filters for Akismet and Defensio as well as a Default Filter.

For a Site (maybe later: for a Section) one can activate and configure which
spam filters are active. One can also change the order in which the spam filters
will be run.

When a Comment is created a spam filter chain is assembled and run. Each filter
can add to the spam analysis results. The results are then accumulated to a
final spaminess value. The individual analysis results can be saved for
statistical reports.

Filters can decide to halt the execution of futher filters on certain conditions.
E.g. when the user is logged in with a certain role a filter might skip executing
additional filters and report a spaminess of 0.

After the filter chain has been run the application judges how to handle the
comment. It might be approved, pushed to the moderation queue, marked as spam
or even deleted.

In any case when a Comment is eventually marked as ham or spam by either the
application or the user every filter is given the chance to report back to
their backend if the spam status does not match their initial analysis.

class Comment
acts_as_spam_report_set
end

acts_as_spam_report_set
has_many :spam_reports
attr :spaminess

def add_spam_report(filter, result)
spam_reports << SpamReport.create! :priority => filter.priority, ...
end

def update_spaminess
sum = spam_reports.inject(0){|report, sum| sum += report.spaminess }
self.spaminess = sum / spam_reports.size
end

class SpamReport
attr :priority
attr :engine
attr :spaminess
attr :data
end


# Sanitizing input

contact xss_terminate developer regarding improvements/refactorings
Expand Down
10 changes: 9 additions & 1 deletion db/schema.rb
Expand Up @@ -107,7 +107,7 @@
t.integer "approved", :default => 0, :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "spam_info"
t.text "spam_info"
end

create_table "content_versions", :force => true do |t|
Expand Down Expand Up @@ -229,6 +229,14 @@
t.text "spam_options"
end

create_table "spam_reports", :force => true do |t|
t.integer "subject_id"
t.string "subject_type"
t.string "engine"
t.float "spaminess"
t.text "data"
end

create_table "taggings", :force => true do |t|
t.integer "tag_id"
t.integer "taggable_id"
Expand Down
2 changes: 1 addition & 1 deletion spec/controllers/comments_controller_spec.rb
Expand Up @@ -58,7 +58,7 @@

it "checks the comment's spaminess" do
url = "http://test.host/sections/1/articles/an-article"
@comment.should_receive(:check_spam).with(url, :authenticated => false)
@comment.should_receive(:check_approval).with(url, :authenticated => false)
act!
end
end
Expand Down
23 changes: 13 additions & 10 deletions spec/models/comment_spec.rb
Expand Up @@ -153,34 +153,37 @@

describe Comment, "spam control" do
before :each do
@section = stub('section', :check_comment => {:spam => false}, :approve_comments? => false)
@report = SpamReport.new(:engine => name, :spaminess => 0, :data => {:spam => false, :spaminess => 0, :signature => 'signature'})
@spam_engine = stub('spam_engine', :check_comment => @report)
@section = stub('section', :spam_engine => @spam_engine, :approve_comments? => false)

@comment = Comment.new
@comment.stub!(:section).and_return @section
@url = 'http://www.domain.org/an-article'
@context = {:url => 'http://www.domain.org/an-article'}
end

describe "#check_spam" do
describe "#check_approval" do
it "saves the spam info hash as returned by Section#check_comment" do
@comment.should_receive(:update_attributes).with hash_including(:spam_info => {:spam => false})
@comment.check_spam @url
@comment.check_approval @context
end

it "approves the comment when the spam info hash contains :spam => false" do
@section.stub!(:check_comment).and_return :spam => false
@comment.should_receive(:update_attributes).with hash_including(:approved => true)
@comment.check_spam @url
@comment.check_approval @context
end

it "disapproves the comment when the spam info hash contains :spam => true" do
@section.stub!(:check_comment).and_return :spam => true
@comment.should_receive(:update_attributes).with hash_including(:approved => false)
@comment.check_spam @url
@comment.check_approval @context
end

it "approves the comment when Section#approve_comments? is true" do
@section.stub!(:approve_comments?).and_return true
@comment.should_receive(:update_attributes).with hash_including(:approved => true)
@comment.check_spam @url
@comment.check_approval @context
end
end

Expand All @@ -194,20 +197,20 @@
# describe '#check_comment' do
# it "approves the comment when the site's spam_option :engine is 'None' and approve_comments is true" do
# sites(:site_1).update_attributes :spam_options => {:engine => 'None', :approve_comments => true}
# @comment.check_spam('http://www.example.org/an-article', @comment)
# @comment.check_approval('http://www.example.org/an-article', @comment)
# @comment.approved?.should be_true
# end
#
# it "does not approve the comment when the site's spam_option :engine is 'None' and approve_comments is not true" do
# sites(:site_1).update_attributes :spam_options => {:engine => 'None', :approve_comments => false}
# @comment.check_spam('http://www.example.org/an-article', @comment)
# @comment.check_approval('http://www.example.org/an-article', @comment)
# @comment.approved?.should be_false
# end
#
# it "calls #check_comment on the None SpamEngine when the site's spam_option :engine is 'None'" do
# sites(:site_1).update_attributes :spam_options => {:engine => 'None', :approve_comments => false}
# @comment.section.site.spam_engine.should be_instance_of(SpamEngine::None)
# @comment.check_spam('http://www.example.org/an-article', @comment)
# @comment.check_approval('http://www.example.org/an-article', @comment)
# @comment.spam_info.should == {}
# end
# end
Expand Down
100 changes: 0 additions & 100 deletions spec/models/spam/akismet.rb

This file was deleted.

107 changes: 0 additions & 107 deletions spec/models/spam/defensio.rb

This file was deleted.

0 comments on commit 391423f

Please sign in to comment.