diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..763b7d8 --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +# A sample Gemfile +source "http://rubygems.org" + +# gem "rails" +gem "rspec" +gem "flexmock" +gem "net-dns" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..2f45105 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,24 @@ +GEM + remote: http://rubygems.org/ + specs: + diff-lcs (1.1.2) + flexmock (0.8.11) + net-dns (0.6.1) + rspec (2.0.1) + rspec-core (~> 2.0.1) + rspec-expectations (~> 2.0.1) + rspec-mocks (~> 2.0.1) + rspec-core (2.0.1) + rspec-expectations (2.0.1) + diff-lcs (>= 1.1.2) + rspec-mocks (2.0.1) + rspec-core (~> 2.0.1) + rspec-expectations (~> 2.0.1) + +PLATFORMS + ruby + +DEPENDENCIES + flexmock + net-dns + rspec diff --git a/lib/project_honeypot.rb b/lib/project_honeypot.rb index 833a6b0..9767f96 100644 --- a/lib/project_honeypot.rb +++ b/lib/project_honeypot.rb @@ -1,9 +1,9 @@ -require 'net/dns' +require 'net/dns/resolver' require File.dirname(__FILE__) + "/project_honeypot/url.rb" require File.dirname(__FILE__) + "/project_honeypot/base.rb" module ProjectHoneypot - def lookup(api_key, url) + def self.lookup(api_key, url) searcher = Base.new(api_key) searcher.lookup(url) end diff --git a/lib/project_honeypot/base.rb b/lib/project_honeypot/base.rb index d410e7f..e08cb03 100644 --- a/lib/project_honeypot/base.rb +++ b/lib/project_honeypot/base.rb @@ -1,10 +1,25 @@ +module ProjectHoneypot class Base def initialize(api_key) @api_key = api_key end - def lookup(url) + def lookup(ip_address) + ip_address = url_to_ip(ip_address) + reversed_ip = ip_address.split(".").reverse.join(".") + honeypot_score = extract_ip_address(Net::DNS::Resolver.start("#{@api_key}.#{reversed_ip}.dnsbl.httpbl.org")) + Url.new(ip_address, honeypot_score) + end + private + + def url_to_ip(url) + return url if url.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) + extract_ip_address(Net::DNS::Resolver.start(url)) + end + + def extract_ip_address(dns_response) + dns_response.answer.first.to_s.split.last end end - +end diff --git a/lib/project_honeypot/url.rb b/lib/project_honeypot/url.rb index 46d5e3d..9dee9e3 100644 --- a/lib/project_honeypot/url.rb +++ b/lib/project_honeypot/url.rb @@ -1,4 +1,52 @@ +module ProjectHoneypot class Url + attr_reader :ip_address, :last_activity, :score, :offenses + def initialize(ip_address, honeypot_response) + @ip_address = ip_address + @safe = honeypot_response.nil? + process_score(honeypot_response) + end + def safe? + @safe + end + + def comment_spammer? + @offenses.include?(:comment_spammer) + end + + def harvester? + @offenses.include?(:harvester) + end + + def suspicious? + @offenses.include?(:suspicious) + end + + private + + def process_score(honeypot_response) + if honeypot_response.nil? + @last_activity = nil + @score = 0 + @offenses = [] + else + hp_array = honeypot_response.split(".") + @last_activity = hp_array[1].to_i + @score = hp_array[2].to_i + @offenses = set_offenses(hp_array[3]) + end + end + + def set_offenses(offense_code) + offense_code = offense_code.to_i + offenses = [] + offenses << :comment_spammer if offense_code/4 == 1 + offense_code = offense_code % 4 + offenses << :harvester if offense_code/2 == 1 + offense_code = offense_code % 2 + offenses << :suspicious if offense_code == 1 + offenses + end end - +end diff --git a/lib/spec/base_spec.rb b/lib/spec/base_spec.rb deleted file mode 100644 index e69de29..0000000 diff --git a/lib/spec/url_spec.rb b/lib/spec/url_spec.rb deleted file mode 100644 index e69de29..0000000 diff --git a/project-honeypot.gemspec b/project-honeypot.gemspec index 0876fd4..367d0fc 100644 --- a/project-honeypot.gemspec +++ b/project-honeypot.gemspec @@ -7,6 +7,7 @@ Gem::Specification.new do |s| s.summary = %q{Project-Honeypot provides a programatic interface to the Project Honeypot services.} s.homepage = %q{http://teachmetocode.com/} s.description = %q{{Project-Honeypot provides a programatic interface to the Project Honeypot services. It can be used to identify spammers, bogus commenters, and harvesters. You will need a FREE api key from http://projecthoneypot.org} + s.add_dependency('net-dns') s.files = [ "README", "MIT-LICENSE", "lib/project_honeypot.rb", diff --git a/spec/base_spec.rb b/spec/base_spec.rb new file mode 100644 index 0000000..5b9acb5 --- /dev/null +++ b/spec/base_spec.rb @@ -0,0 +1,22 @@ +require "spec_helper" + +describe ProjectHoneypot::Base do + describe "with honeypot response" do + before(:each) do + flexmock(Net::DNS::Resolver, :start => flexmock("answer", :answer => ["somedomain.httpbl.org A Name 127.1.63.5"])) + @base = ProjectHoneypot::Base.new("abcdefghijklmnop") + end + + it "returns a Url object" do + url = @base.lookup("127.10.10.5") + url.should be_a ProjectHoneypot::Url + url.last_activity.should == 1 + url.score.should == 63 + end + + it "looks up non-ip addresses" do + url = @base.lookup("iamspam.com") + Net::DNS::Resolver.should_receive(:start).with("iamspam.com") + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..c760d31 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,9 @@ +require "rubygems" +require "bundler/setup" +require "rspec" +require "flexmock" +require File.dirname(__FILE__) + "/../lib/project_honeypot" + +RSpec.configure do |config| + config.mock_with :flexmock +end diff --git a/spec/url_spec.rb b/spec/url_spec.rb new file mode 100644 index 0000000..484258f --- /dev/null +++ b/spec/url_spec.rb @@ -0,0 +1,35 @@ +require "spec_helper" + +describe ProjectHoneypot::Url do + describe "with honeypot response" do + before(:each) do + @url = ProjectHoneypot::Url.new("teachmetocode.com", "127.1.63.3") + end + + it "is safe" do + @url.should_not be_safe + end + + it "has the correct latest activity" do + @url.last_activity.should == 1 + end + + it "has the correct score" do + @url.score.should == 63 + end + + it "has the correct offenses" do + @url.offenses.should include(:suspicious) + @url.offenses.should include(:harvester) + @url.offenses.should_not include(:comment_spammer) + @url.should be_suspicious + @url.should be_harvester + @url.should_not be_comment_spammer + end + end + + describe "with nil honeypot response" do + subject { @url = ProjectHoneypot::Url.new("teachmetocode.com", nil) } + it { should be_safe } + end +end