akismetor 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.rvmrc +3 -0
- data/Gemfile +4 -0
- data/MIT_LICENSE +20 -0
- data/README +89 -0
- data/Rakefile +2 -0
- data/akismetor.gemspec +23 -0
- data/lib/akismetor.rb +57 -0
- data/lib/akismetor/version.rb +3 -0
- data/spec/akismetor_spec.rb +116 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +34 -0
- metadata +98 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
data/Gemfile
ADDED
data/MIT_LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Ryan Bates
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
= Now with TypePad support!
|
2
|
+
|
3
|
+
Akismetor now supports the free TypePad API in addition to Akismet.
|
4
|
+
|
5
|
+
To switch to TypePad, add
|
6
|
+
:provider => :typepad
|
7
|
+
to your attributes hash (and don't forget to set your API key to your TypePad key).
|
8
|
+
|
9
|
+
If you wish to continue using Akismet, you need do nothing.
|
10
|
+
|
11
|
+
= Akismetor 1.1
|
12
|
+
|
13
|
+
This version includes rSpec tests and a method to verify the Akismet key.
|
14
|
+
|
15
|
+
This plugin was originally created by Ryan Bates (Railscasts episode 65), being forked from http://svn.railscasts.com/public/plugins/akismetor
|
16
|
+
|
17
|
+
This plugin provides the Akismet class which you can use to communicate with Akismet. Akismet [http://akismet.com/] is a collaborative spam filtering service.
|
18
|
+
|
19
|
+
You can use the class Akismet and its methods, wherever you want inside your Rails application.
|
20
|
+
|
21
|
+
== Install:
|
22
|
+
|
23
|
+
./script/plugin install git://github.com/levycarneiro/akismetor
|
24
|
+
|
25
|
+
|
26
|
+
== Usage:
|
27
|
+
|
28
|
+
# submits key to Akismet, and returns a string with "valid" or "invalid".
|
29
|
+
Akismetor.valid_key?(attributes)
|
30
|
+
|
31
|
+
# submits comment to Akismet, and returns true if the comment is spam, and false in case it's not.
|
32
|
+
Akismetor.spam?(attributes)
|
33
|
+
|
34
|
+
# submits hash as spam to Akismet. Returns a message string.
|
35
|
+
Akismetor.submit_spam(attributes)
|
36
|
+
|
37
|
+
# submits hash as ham to Akismet. Returns a message string.
|
38
|
+
Akismetor.submit_ham(attributes)
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
Let's see a real usage:
|
43
|
+
|
44
|
+
comment_attributes = {
|
45
|
+
:key => '123456789',
|
46
|
+
:blog => 'http://www.my-site.com',
|
47
|
+
:user_ip => '200.10.20.30',
|
48
|
+
:user_agent => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.0.3) Gecko/2008092414 Firefox/3.0.3',
|
49
|
+
:referrer => 'http://www.another-site.com',
|
50
|
+
:permalink => 'http://www.my-site.com/posts/2',
|
51
|
+
:comment_type => 'comment',
|
52
|
+
:comment_author => 'John Doe',
|
53
|
+
:comment_author_email => 'john@doe.com',
|
54
|
+
:comment_author_url => 'http://www.doe.com',
|
55
|
+
:comment_content => 'I beg to differ....'
|
56
|
+
}
|
57
|
+
|
58
|
+
check = Akismetor.spam?(comment_attributes)
|
59
|
+
puts "Is this spam? #{check.to_s}."
|
60
|
+
|
61
|
+
== The Akismet API
|
62
|
+
|
63
|
+
Akismet API Documentation Version 1.1 is at http://akismet.com/development/api/
|
64
|
+
|
65
|
+
blog (required)
|
66
|
+
The front page or home URL of the instance making the request. For a blog or wiki this would be the front page. Note: Must be a full URI, including http://.
|
67
|
+
user_ip (required)
|
68
|
+
IP address of the comment submitter.
|
69
|
+
user_agent (required)
|
70
|
+
User agent information.
|
71
|
+
referrer (note spelling)
|
72
|
+
The content of the HTTP_REFERER header should be sent here.
|
73
|
+
permalink
|
74
|
+
The permanent location of the entry the comment was submitted to.
|
75
|
+
comment_type
|
76
|
+
May be blank, comment, trackback, pingback, or a made up value like "registration".
|
77
|
+
comment_author
|
78
|
+
Submitted name with the comment
|
79
|
+
comment_author_email
|
80
|
+
Submitted email address
|
81
|
+
comment_author_url
|
82
|
+
Commenter URL.
|
83
|
+
comment_content
|
84
|
+
The content that was submitted.
|
85
|
+
Other server enviroment variables
|
86
|
+
In PHP there is an array of enviroment variables called $_SERVER which contains information about the web server itself as well as a key/value for every HTTP header sent with the request. This data is highly useful to Akismet as how the submited content interacts with the server can be very telling, so please include as much information as possible.
|
87
|
+
|
88
|
+
This call returns either "true" or "false" as the body content. True means that the comment is spam and false means that it isn't spam. If you are having trouble triggering you can send "viagra-test-123" as the author and it will trigger a true response, always.
|
89
|
+
|
data/Rakefile
ADDED
data/akismetor.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "akismetor/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "akismetor"
|
7
|
+
s.version = Akismetor::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Robby Grossman", "Ryan Bates", "Levy Carneiro"]
|
10
|
+
s.email = ["robby@freerobby.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Spam protection with Akismet and Typepad}
|
13
|
+
s.description = %q{Spam protection with Akismet and Typepad}
|
14
|
+
|
15
|
+
s.rubyforge_project = "akismetor"
|
16
|
+
|
17
|
+
s.add_development_dependency "rspec", ">= 2.4.0"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
end
|
data/lib/akismetor.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
class Akismetor
|
2
|
+
attr_accessor :attributes
|
3
|
+
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
API_HOST_AKISMET = "rest.akismet.com"
|
7
|
+
API_HOST_TYPEPAD = "api.antispam.typepad.com"
|
8
|
+
|
9
|
+
# Does a key-check on Akismet so you know you can actually use a specific key.
|
10
|
+
# Returns "valid" or "invalid" depending on response.
|
11
|
+
def self.valid_key?(attributes)
|
12
|
+
self.new(attributes).execute('verify-key')
|
13
|
+
end
|
14
|
+
|
15
|
+
# Does a comment-check on Akismet with the submitted hash.
|
16
|
+
# Returns true or false depending on response.
|
17
|
+
def self.spam?(attributes)
|
18
|
+
self.new(attributes).execute('comment-check') != "false"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Does a submit-spam on Akismet with the submitted hash.
|
22
|
+
# Use this when Akismet incorrectly approves a spam comment.
|
23
|
+
def self.submit_spam(attributes)
|
24
|
+
self.new(attributes).execute('submit-spam')
|
25
|
+
end
|
26
|
+
|
27
|
+
# Does a submit-ham on Akismet with the submitted hash.
|
28
|
+
# Use this for a false positive, when Akismet incorrectly rejects a normal comment.
|
29
|
+
def self.submit_ham(attributes)
|
30
|
+
self.new(attributes).execute('submit-ham')
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(attributes)
|
34
|
+
@attributes = attributes
|
35
|
+
end
|
36
|
+
|
37
|
+
def execute(command)
|
38
|
+
host = (@attributes[:provider] != :typepad) ? API_HOST_AKISMET : API_HOST_TYPEPAD
|
39
|
+
host_prefix = "#{@attributes[:key]}." if attributes[:key] && command != 'verify-key'
|
40
|
+
http = Net::HTTP.new("#{host_prefix}#{host}", 80)
|
41
|
+
http.post("/1.1/#{command}", attributes_for_post, http_headers).body
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def http_headers
|
47
|
+
{
|
48
|
+
'User-Agent' => 'Akismetor Rails Plugin/1.1',
|
49
|
+
'Content-Type' => 'application/x-www-form-urlencoded'
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def attributes_for_post
|
54
|
+
result = attributes.map { |k, v| "#{k}=#{v}" }.join('&')
|
55
|
+
URI.escape(result)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/akismetor'
|
3
|
+
|
4
|
+
module AkismetorSpecHelper
|
5
|
+
def valid_attributes
|
6
|
+
{
|
7
|
+
:key => 'YourApiKey',
|
8
|
+
:blog => 'http://www.my-site.com',
|
9
|
+
:user_ip => '200.10.20.30',
|
10
|
+
:user_agent => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.0.3) Gecko/2008092414 Firefox/3.0.3',
|
11
|
+
:referrer => 'http://www.previous-site.com',
|
12
|
+
:permalink => 'http://www.my-site.com',
|
13
|
+
:comment_type => 'comment',
|
14
|
+
:comment_author => 'Joe Dude',
|
15
|
+
:comment_author_email => 'some-email@some-host.com',
|
16
|
+
:comment_author_url => 'http://www.author-s-site.com',
|
17
|
+
:comment_content => 'this is a normal comment'
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def invalid_attributes
|
22
|
+
valid_attributes.with(:comment_author => 'viagra-test-123')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe Akismetor do
|
27
|
+
include AkismetorSpecHelper
|
28
|
+
|
29
|
+
describe "plugin requirements" do
|
30
|
+
|
31
|
+
def mock_akismet(value)
|
32
|
+
@response = stub("response", :body => value)
|
33
|
+
@http = stub("http", :post => @response)
|
34
|
+
end
|
35
|
+
|
36
|
+
it ".spam? should convert provider's string 'true' to boolean true" do
|
37
|
+
mock_akismet('true')
|
38
|
+
Net::HTTP.should_receive(:new).and_return(@http)
|
39
|
+
Akismetor.spam?(invalid_attributes).should be_true
|
40
|
+
end
|
41
|
+
|
42
|
+
it ".spam? should convert provier's string 'false' to boolean false" do
|
43
|
+
mock_akismet('false')
|
44
|
+
Net::HTTP.should_receive(:new).and_return(@http)
|
45
|
+
Akismetor.spam?(invalid_attributes).should be_false
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "with akismet" do
|
49
|
+
before do
|
50
|
+
@implicit_attributes = valid_attributes
|
51
|
+
@explicit_attributes = valid_attributes.with(:provider => :akismet)
|
52
|
+
end
|
53
|
+
|
54
|
+
it ".valid_key? should connect to host 'rest.akismet.com' " do
|
55
|
+
mock_akismet('true')
|
56
|
+
Net::HTTP.should_receive(:new).exactly(:twice).with('rest.akismet.com', anything()).and_return(@http)
|
57
|
+
Akismetor.valid_key?(@implicit_attributes)
|
58
|
+
Akismetor.valid_key?(@explicit_attributes)
|
59
|
+
end
|
60
|
+
|
61
|
+
it ".spam? should connect to host 'YourApiKey.rest.akismet.com' " do
|
62
|
+
mock_akismet('true')
|
63
|
+
Net::HTTP.should_receive(:new).exactly(:twice).with('YourApiKey.rest.akismet.com', anything()).and_return(@http)
|
64
|
+
Akismetor.spam?(@implicit_attributes)
|
65
|
+
Akismetor.spam?(@explicit_attributes)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "with typepad" do
|
70
|
+
before do
|
71
|
+
@attributes = valid_attributes.with(:provider => :typepad)
|
72
|
+
end
|
73
|
+
|
74
|
+
it ".valid_key? should connect to host 'api.antispam.typepad.com' " do
|
75
|
+
mock_akismet('true')
|
76
|
+
Net::HTTP.should_receive(:new).with('api.antispam.typepad.com', anything()).and_return(@http)
|
77
|
+
Akismetor.valid_key?(@attributes)
|
78
|
+
end
|
79
|
+
|
80
|
+
it ".spam? should connect to host 'YourApiKey.api.antispam.typepad.com' " do
|
81
|
+
mock_akismet('true')
|
82
|
+
Net::HTTP.should_receive(:new).with('YourApiKey.api.antispam.typepad.com', anything()).and_return(@http)
|
83
|
+
Akismetor.spam?(@attributes)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "provider commands" do
|
89
|
+
|
90
|
+
before(:each) do
|
91
|
+
@response = stub("response", :body => 'true')
|
92
|
+
@http = stub("http", :post => @response)
|
93
|
+
Net::HTTP.should_receive(:new).and_return(@http)
|
94
|
+
end
|
95
|
+
|
96
|
+
it ".valid_key? should run provider's command 'verify-key' " do
|
97
|
+
@http.should_receive(:post).with('/1.1/verify-key', anything(), anything()).and_return(@response)
|
98
|
+
Akismetor.valid_key?(valid_attributes)
|
99
|
+
end
|
100
|
+
|
101
|
+
it ".spam? should run provider's command 'comment-check' " do
|
102
|
+
@http.should_receive(:post).with('/1.1/comment-check', anything(), anything()).and_return(@response)
|
103
|
+
Akismetor.spam?(valid_attributes)
|
104
|
+
end
|
105
|
+
|
106
|
+
it ".submit_spam should run provider's command 'submit-spam' " do
|
107
|
+
@http.should_receive(:post).with('/1.1/submit-spam', anything(), anything()).and_return(@response)
|
108
|
+
Akismetor.submit_spam(valid_attributes)
|
109
|
+
end
|
110
|
+
|
111
|
+
it ".submit_ham should run provider's command 'submit-ham' " do
|
112
|
+
@http.should_receive(:post).with('/1.1/submit-ham', anything(), anything()).and_return(@response)
|
113
|
+
Akismetor.submit_ham(valid_attributes)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
# rSpec Hash additions. From
|
4
|
+
# * http://wincent.com/knowledge-base/Fixtures_considered_harmful%3F
|
5
|
+
# * Neil Rahilly
|
6
|
+
class Hash
|
7
|
+
|
8
|
+
# Filter keys out of a Hash.
|
9
|
+
# { :a => 1, :b => 2, :c => 3 }.except(:a)
|
10
|
+
# => { :b => 2, :c => 3 }
|
11
|
+
|
12
|
+
def except(*keys)
|
13
|
+
self.reject { |k,v| keys.include?(k || k.to_sym) }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Override some keys.
|
17
|
+
# { :a => 1, :b => 2, :c => 3 }.with(:a => 4)
|
18
|
+
# => { :a => 4, :b => 2, :c => 3 }
|
19
|
+
|
20
|
+
def with(overrides = {})
|
21
|
+
self.merge overrides
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns a Hash with only the pairs identified by +keys+.
|
25
|
+
# { :a => 1, :b => 2, :c => 3 }.only(:a)
|
26
|
+
# => { :a => 1 }
|
27
|
+
|
28
|
+
def only(*keys)
|
29
|
+
self.reject { |k,v| !keys.include?(k || k.to_sym) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
RSpec::configure do |config|
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: akismetor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Robby Grossman
|
14
|
+
- Ryan Bates
|
15
|
+
- Levy Carneiro
|
16
|
+
autorequire:
|
17
|
+
bindir: bin
|
18
|
+
cert_chain: []
|
19
|
+
|
20
|
+
date: 2011-01-20 00:00:00 -05:00
|
21
|
+
default_executable:
|
22
|
+
dependencies:
|
23
|
+
- !ruby/object:Gem::Dependency
|
24
|
+
name: rspec
|
25
|
+
prerelease: false
|
26
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
hash: 31
|
32
|
+
segments:
|
33
|
+
- 2
|
34
|
+
- 4
|
35
|
+
- 0
|
36
|
+
version: 2.4.0
|
37
|
+
type: :development
|
38
|
+
version_requirements: *id001
|
39
|
+
description: Spam protection with Akismet and Typepad
|
40
|
+
email:
|
41
|
+
- robby@freerobby.com
|
42
|
+
executables: []
|
43
|
+
|
44
|
+
extensions: []
|
45
|
+
|
46
|
+
extra_rdoc_files: []
|
47
|
+
|
48
|
+
files:
|
49
|
+
- .gitignore
|
50
|
+
- .rvmrc
|
51
|
+
- Gemfile
|
52
|
+
- MIT_LICENSE
|
53
|
+
- README
|
54
|
+
- Rakefile
|
55
|
+
- akismetor.gemspec
|
56
|
+
- lib/akismetor.rb
|
57
|
+
- lib/akismetor/version.rb
|
58
|
+
- spec/akismetor_spec.rb
|
59
|
+
- spec/spec.opts
|
60
|
+
- spec/spec_helper.rb
|
61
|
+
has_rdoc: true
|
62
|
+
homepage: ""
|
63
|
+
licenses: []
|
64
|
+
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 3
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
version: "0"
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
hash: 3
|
85
|
+
segments:
|
86
|
+
- 0
|
87
|
+
version: "0"
|
88
|
+
requirements: []
|
89
|
+
|
90
|
+
rubyforge_project: akismetor
|
91
|
+
rubygems_version: 1.3.7
|
92
|
+
signing_key:
|
93
|
+
specification_version: 3
|
94
|
+
summary: Spam protection with Akismet and Typepad
|
95
|
+
test_files:
|
96
|
+
- spec/akismetor_spec.rb
|
97
|
+
- spec/spec.opts
|
98
|
+
- spec/spec_helper.rb
|