Compare commits
	
		
			14 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9533bf2c66 | |||
| c4bde860e2 | |||
| 415f7c9d24 | |||
| 707b115428 | |||
| 15ea3a4f67 | |||
| a7e59ef5c8 | |||
| 6bb140e738 | |||
| 2870baff6e | |||
|   | 56166bbb3c | ||
|   | 5585e5d92e | ||
|   | a1a7beb464 | ||
|   | 2f87b63c18 | ||
|   | e0b488868a | ||
|   | 1a3eeaf4cf | 
| @ -1,4 +1,5 @@ | ||||
| Copyright (c) 2010 Charles Max Wood chuck@teachmetocode.com | ||||
| Copyright (c) 2013 Guillaume DOTT guillaume+github@dott.fr | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person | ||||
| obtaining a copy of this software and associated documentation | ||||
|  | ||||
							
								
								
									
										37
									
								
								README.rdoc
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								README.rdoc
									
									
									
									
									
								
							| @ -1,28 +1,40 @@ | ||||
| = Project Honeypot | ||||
| 
 | ||||
| Project Honeypot is a programmatic interface to the Project Honeypot HTTP:BL service for identifying suspicious ip addresses. | ||||
| This Gem was built to filter out spammers on http://www.tweetburner.com. | ||||
| 
 | ||||
| It is a handy thing to be able to identify spammers, harvesters, and other suspicious IP addresses if you're worried about who might be abusing your service. | ||||
| 
 | ||||
| = Requirements | ||||
| == Requirements | ||||
| 
 | ||||
| This Gem requires that you have an Http:BL API key from Project Honeypot. You can get one at http://projecthhoneypot.org | ||||
| 
 | ||||
| = Usage | ||||
| == Configuration | ||||
| 
 | ||||
|   ProjectHoneypot.configure do | ||||
|     @api_key = 'api_key' | ||||
|     @score = 42 | ||||
|     @last_activity = 10 | ||||
|     @offenses = [:comment_spammer, :suspicious, :harvester] | ||||
|   end | ||||
| 
 | ||||
| == Usage | ||||
| 
 | ||||
|   require 'project_honeypot' | ||||
| 
 | ||||
| HTTP:BL lookups through Project Honeypot result in a Url object that gives you the risk score, last activity, and types of offenses the ip address is listed for. | ||||
| 
 | ||||
| The score is worse the higher it is and the last_activity is in days. | ||||
| 
 | ||||
| == Example #1: Suspicious IP Address | ||||
| 
 | ||||
| Given an api key of "abcdefghijkl" | ||||
| === Example #1: Suspicious IP Address | ||||
| 
 | ||||
|   @listing = ProjectHoneypot.lookup("abcdefghijkl", "192.168.1.1") | ||||
|   @listing = ProjectHoneypot.lookup("<ip_address>", "<api_key>") | ||||
|   @listing.safe? | ||||
|   # => false | ||||
| 
 | ||||
|   @listing.safe?(score: 64, last_activity: 10, offenses: [:comment_spammer]) | ||||
|   # => true | ||||
| 
 | ||||
|   @listing.ip_address | ||||
|   # => "192.168.1.1" | ||||
| 
 | ||||
| @ -44,9 +56,12 @@ Given an api key of "abcdefghijkl" | ||||
|   @listing.harvester? | ||||
|   # => false | ||||
| 
 | ||||
| == Example #2: Safe IP Address | ||||
|   @listing.search_engine? | ||||
|   # => false | ||||
| 
 | ||||
|   @listing = ProjectHoneypot.lookup("abcdefghijkl", "192.168.1.1") | ||||
| === Example #2: Safe IP Address | ||||
| 
 | ||||
|   @listing = ProjectHoneypot.lookup("<ip_address>") | ||||
|   @listing.safe? | ||||
|   # => true | ||||
| 
 | ||||
| @ -70,9 +85,3 @@ Given an api key of "abcdefghijkl" | ||||
| 
 | ||||
|   @listing.harvester? | ||||
|   # => false | ||||
| 
 | ||||
| = To Do Items | ||||
| 
 | ||||
| - Cache Responses from Project Honeypot | ||||
| - Allow 'safe?' to be configurable (algorithm based on recency and severity(score)) | ||||
| - A .yml config file | ||||
|  | ||||
							
								
								
									
										5
									
								
								Rakefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Rakefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| require 'rspec/core/rake_task' | ||||
| 
 | ||||
| RSpec::Core::RakeTask.new(:spec) | ||||
| 
 | ||||
| task :default => :spec | ||||
| @ -1 +0,0 @@ | ||||
| require "project_honeypot" | ||||
| @ -1,12 +1,13 @@ | ||||
| require 'net/dns' | ||||
| require "project_honeypot/url" | ||||
| require "project_honeypot/base" | ||||
| require "project_honeypot/rack" | ||||
| require "project_honeypot/rack/header" | ||||
| require "project_honeypot/rack/forbidden" | ||||
| 
 | ||||
| module ProjectHoneypot | ||||
|   class << self | ||||
|     attr_accessor :api_key, :score, :last_activity | ||||
|     attr_accessor :api_key, :score, :last_activity, :offenses | ||||
| 
 | ||||
|     def api_key | ||||
|       raise "ProjectHoneypot really needs its api_key set to work" unless @api_key | ||||
| @ -18,12 +19,12 @@ module ProjectHoneypot | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def self.lookup(api_key_or_url, url=nil) | ||||
|     if url.nil? | ||||
|       url = api_key_or_url | ||||
|       api_key_or_url = ProjectHoneypot.api_key | ||||
|     end | ||||
|     searcher = Base.new(api_key_or_url) | ||||
|   def self.lookup(url, api_key=nil) | ||||
|     api_key ||= ProjectHoneypot.api_key | ||||
| 
 | ||||
|     raise ArgumentError, 'Must specify an API key' unless api_key | ||||
| 
 | ||||
|     searcher = Base.new(api_key) | ||||
|     searcher.lookup(url) | ||||
|   end | ||||
| end | ||||
|  | ||||
							
								
								
									
										10
									
								
								lib/project_honeypot/rack.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/project_honeypot/rack.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| module ProjectHoneypot | ||||
|   class Rack | ||||
|     def initialize(app, options={}) | ||||
|       @app = app | ||||
| 
 | ||||
|       raise ArgumentError, 'Must specify an API key' unless options[:api_key] | ||||
|       ProjectHoneypot.api_key = options[:api_key] | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @ -1,12 +1,6 @@ | ||||
| module ProjectHoneypot::Rack | ||||
|   class Forbidden | ||||
|     def initialize(app, options={}) | ||||
|       @app = app | ||||
| 
 | ||||
|       raise ArgumentError, 'Must specify an API key' unless options[:api_key] | ||||
|       ProjectHoneypot.api_key = options[:api_key] | ||||
|     end | ||||
| 
 | ||||
| module ProjectHoneypot | ||||
|   class Rack | ||||
|     class Forbidden < Rack | ||||
|       def call(env) | ||||
|         request = ::Rack::Request.new(env) | ||||
|         url = ProjectHoneypot.lookup(request.ip) | ||||
| @ -18,4 +12,5 @@ module ProjectHoneypot::Rack | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| @ -1,12 +1,6 @@ | ||||
| module ProjectHoneypot::Rack | ||||
|   class Header | ||||
|     def initialize(app, options={}) | ||||
|       @app = app | ||||
| 
 | ||||
|       raise ArgumentError, 'Must specify an API key' unless options[:api_key] | ||||
|       ProjectHoneypot.api_key = options[:api_key] | ||||
|     end | ||||
| 
 | ||||
| module ProjectHoneypot | ||||
|   class Rack | ||||
|     class Header < Rack | ||||
|       def call(env) | ||||
|         request = ::Rack::Request.new(env) | ||||
|         url = ProjectHoneypot.lookup(request.ip) | ||||
| @ -16,4 +10,5 @@ module ProjectHoneypot::Rack | ||||
|         @app.call(request.env) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| @ -1,6 +1,22 @@ | ||||
| module ProjectHoneypot | ||||
|   class Url | ||||
|     attr_reader :ip_address, :last_activity, :score, :offenses | ||||
|     SEARCH_ENGINES = %w( | ||||
|       Undocumented | ||||
|       AltaVista | ||||
|       Ask | ||||
|       Baidu | ||||
|       Excite | ||||
|       Google | ||||
|       Looksmart | ||||
|       Lycos | ||||
|       MSN | ||||
|       Yahoo | ||||
|       Cuil | ||||
|       InfoSeek | ||||
|       Miscellaneous | ||||
|     ) | ||||
| 
 | ||||
|     attr_reader :ip_address, :last_activity, :score, :offenses, :search_engine | ||||
|     def initialize(ip_address, honeypot_response) | ||||
|       @ip_address = ip_address | ||||
|       @safe = honeypot_response.nil? | ||||
| @ -11,14 +27,25 @@ module ProjectHoneypot | ||||
|       score = hash[:score] || ProjectHoneypot.score | ||||
|       last_activity = hash[:last_activity] || ProjectHoneypot.last_activity | ||||
| 
 | ||||
|       forbidden_offenses = hash[:offenses] || | ||||
|                             ProjectHoneypot.offenses || | ||||
|                             [:comment_spammer, :harvester, :suspicious] | ||||
| 
 | ||||
|       detected_offenses = forbidden_offenses & @offenses | ||||
| 
 | ||||
|       @safe || | ||||
|         detected_offenses.length == 0 || | ||||
|         !( | ||||
|           last_activity.nil? && score.nil? || | ||||
|           !score.nil? && self.score > score || | ||||
|           !last_activity.nil? && self.last_activity > last_activity | ||||
|           !score.nil? && self.score >= score || | ||||
|           !last_activity.nil? && self.last_activity >= last_activity | ||||
|         ) | ||||
|     end | ||||
| 
 | ||||
|     def search_engine? | ||||
|       @offenses.include?(:search_engine) | ||||
|     end | ||||
| 
 | ||||
|     def comment_spammer? | ||||
|       @offenses.include?(:comment_spammer) | ||||
|     end | ||||
| @ -40,11 +67,22 @@ module ProjectHoneypot | ||||
|         @offenses = [] | ||||
|       else | ||||
|         hp_array = honeypot_response.split(".") | ||||
| 
 | ||||
|         if hp_array[3].to_i == 0 | ||||
|           # search engine | ||||
|           @last_activity = nil | ||||
|           @score = 0 | ||||
|           @offenses = [:search_engine] | ||||
|           @search_engine = (hp_array[2].to_i < SEARCH_ENGINES.length ? | ||||
|                             SEARCH_ENGINES[hp_array[2].to_i] : | ||||
|                             SEARCH_ENGINES[0]) | ||||
|         else | ||||
|           @last_activity = hp_array[1].to_i | ||||
|           @score = hp_array[2].to_i | ||||
|           @offenses = set_offenses(hp_array[3]) | ||||
|         end | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     def set_offenses(offense_code) | ||||
|       offense_code = offense_code.to_i | ||||
|  | ||||
| @ -1,3 +1,3 @@ | ||||
| module ProjectHoneypot | ||||
|     VERSION = "0.2.0" | ||||
|     VERSION = "0.3.1" | ||||
| end | ||||
|  | ||||
| @ -10,7 +10,7 @@ Gem::Specification.new do |s| | ||||
|   s.email = ["chuck@teachmetocode.com", "guillaume+github@dott.fr"] | ||||
|   s.summary = %q{Project-Honeypot provides a programatic interface to the Project Honeypot services.} | ||||
|   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.homepage = "" | ||||
|   s.homepage = "https://github.com/gdott9/project_honeypot" | ||||
| 
 | ||||
|   s.files = `git ls-files`.split($/) | ||||
|   s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) } | ||||
| @ -19,5 +19,5 @@ Gem::Specification.new do |s| | ||||
|   s.add_development_dependency 'rspec' | ||||
|   s.add_development_dependency 'flexmock' | ||||
| 
 | ||||
|   s.add_runtime_dependency 'net-dns' | ||||
|   s.add_runtime_dependency 'net-dns', '~> 0.7.1' | ||||
| end | ||||
|  | ||||
| @ -2,20 +2,21 @@ require "spec_helper" | ||||
| 
 | ||||
| describe ProjectHoneypot::Base do | ||||
|   describe "with honeypot response" do | ||||
|     let(:base) { ProjectHoneypot::Base.new("abcdefghijklmnop") } | ||||
|     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 | ||||
|       url = base.lookup("127.10.10.5") | ||||
| 
 | ||||
|       expect(url).to be_a(ProjectHoneypot::Url) | ||||
|       expect(url.last_activity).to eq(1) | ||||
|       expect(url.score).to eq(63) | ||||
|     end | ||||
| 
 | ||||
|     it "looks up non-ip addresses" do | ||||
|       url = @base.lookup("iamspam.com") | ||||
|       url = base.lookup("iamspam.com") | ||||
|       Net::DNS::Resolver.should_receive(:start).with("iamspam.com") | ||||
|     end | ||||
|   end | ||||
|  | ||||
| @ -2,34 +2,51 @@ 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 | ||||
|     let(:url) { ProjectHoneypot::Url.new("127.0.0.1", "127.1.63.3") } | ||||
| 
 | ||||
|     it "is safe" do | ||||
|       @url.should_not be_safe | ||||
|       expect(url.safe?).to be false | ||||
| 
 | ||||
|       expect(url.safe?(score: 63)).to be false | ||||
|       expect(url.safe?(score: 64)).to be true | ||||
| 
 | ||||
|       expect(url.safe?(last_activity: 1)).to be false | ||||
|       expect(url.safe?(last_activity: 2)).to be true | ||||
| 
 | ||||
|       expect(url.safe?(last_activity: 2, score: 64)).to be true | ||||
|       expect(url.safe?(last_activity: 1, score: 64)).to be false | ||||
|       expect(url.safe?(last_activity: 2, score: 63)).to be false | ||||
| 
 | ||||
|       expect(url.safe?(offenses: [:comment_spammer])).to be true | ||||
|       expect(url.safe?(offenses: [:suspicious, :comment_spammer])).to be false | ||||
|     end | ||||
| 
 | ||||
|     it "has the correct latest activity" do | ||||
|       @url.last_activity.should == 1 | ||||
|       expect(url.last_activity).to eq(1) | ||||
|     end | ||||
| 
 | ||||
|     it "has the correct score" do | ||||
|       @url.score.should == 63 | ||||
|       expect(url.score).to eq(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 | ||||
|       expect(url.offenses).to include(:suspicious) | ||||
|       expect(url.offenses).to include(:harvester) | ||||
|       expect(url.offenses).to_not include(:comment_spammer) | ||||
|       expect(url).to be_suspicious | ||||
|       expect(url).to be_harvester | ||||
|       expect(url).to_not be_comment_spammer | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe "with search engine honeypot response" do | ||||
|     subject { ProjectHoneypot::Url.new("127.0.0.1", "127.0.9.0") } | ||||
|     it { should be_safe } | ||||
|     it { should be_search_engine } | ||||
|   end | ||||
| 
 | ||||
|   describe "with nil honeypot response" do | ||||
|     subject { @url = ProjectHoneypot::Url.new("teachmetocode.com", nil) } | ||||
|     subject { ProjectHoneypot::Url.new("127.0.0.1", nil) } | ||||
|     it { should be_safe } | ||||
|   end | ||||
| end | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user