Permalink
Browse files

First pass at honeypot captcha

  • Loading branch information...
1 parent fe48ff0 commit 066aca7bdd3b026c7a2b13fdae575c889c1a9d18 curtis committed Apr 10, 2010
Showing with 188 additions and 54 deletions.
  1. +18 −17 LICENSE
  2. +62 −0 README.markdown
  3. +0 −17 README.rdoc
  4. +2 −2 Rakefile
  5. +1 −1 VERSION
  6. +49 −0 honeypot-captcha.gemspec
  7. +23 −0 lib/honeypot-captcha.rb
  8. +33 −0 lib/honeypot-captcha/form_tag_helper.rb
  9. +0 −7 spec/honeypot-captcha_spec.rb
  10. +0 −1 spec/spec.opts
  11. +0 −9 spec/spec_helper.rb
View
@@ -1,20 +1,21 @@
-Copyright (c) 2009 curtis
+The MIT License
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
+Copyright (c) 2010 Curtis Miller
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
View
@@ -0,0 +1,62 @@
+# honeypot-captcha
+
+A simple way to add honeypot captchas in your Rails forms.
+
+## Honeypot Captcha
+
+Honeypot captchas work off the premise that you can present different form
+fields to a spam bot than you do to a real user. Spam bots will typically try
+to fill all fields in a form and will not take into account CSS styles.
+
+We add bogus fields to a form and then check to see if those fields are
+submitted with values. If they are, we assume that we encountered a spam bot.
+
+# Usage
+
+I've tried to make it pretty simple to add a honeypot captcha, but I'm open to
+any suggestions you may have.
+
+## form_for
+
+Simply specify that the form has a honeypot in the HTML options hash:
+
+<% form_for Comment.new, :html => { :honeypot => true } do |form| -%>
+ ...
+<% end -%>
+
+## form_tag with block
+
+Simply specify that the form has a honeypot in the options hash:
+
+<% form_tag comments_path, :honeypot => true do -%>
+ ...
+<% end -%>
+
+## form_tag without block
+
+Simply specify that the form has a honeypot in the options hash:
+
+<%= form_tag comments_path, :honeypot => true -%>
+ ...
+</form>
+
+### References
+
+* [Honeypot Captcha by Phil Haack](http://haacked.com/archive/2007/09/11/honeypot-captcha.aspx)
+* [Stopping spambots with hashes and honeypots](http://nedbatchelder.com/text/stopbots.html)
+
+## Note on Patches/Pull Requests
+
+* Fork the project.
+* Make your feature addition or bug fix.
+* Add tests for it. This is important so I don't break it in a future version unintentionally.
+* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
+* Send me a pull request. Bonus points for topic branches.
+
+## Author
+
+Written by [Curtis Miller](http://millarian.com) of [Flatterline](http://flatterline.com)
+
+## Copyright
+
+Copyright (c) 2010 Curtis Miller. See LICENSE for details.
View
@@ -1,17 +0,0 @@
-= honeypot-captcha
-
-Description goes here.
-
-== Note on Patches/Pull Requests
-
-* Fork the project.
-* Make your feature addition or bug fix.
-* Add tests for it. This is important so I don't break it in a
- future version unintentionally.
-* Commit, do not mess with rakefile, version, or history.
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
-* Send me a pull request. Bonus points for topic branches.
-
-== Copyright
-
-Copyright (c) 2010 curtis. See LICENSE for details.
View
@@ -5,8 +5,8 @@ begin
require 'jeweler'
Jeweler::Tasks.new do |gem|
gem.name = "honeypot-captcha"
- gem.summary = %Q{TODO: one-line summary of your gem}
- gem.description = %Q{TODO: longer description of your gem}
+ gem.summary = %Q{A simple way to add honeypot captchas to Rails forms}
+ gem.description = %Q{A simple way to add honeypot captchas to Rails forms}
gem.email = "curtis@flatterline.com"
gem.homepage = "http://github.com/curtis/honeypot-captcha"
gem.authors = ["curtis"]
View
@@ -1 +1 @@
-0.0.0
+0.0.1
@@ -0,0 +1,49 @@
+# Generated by jeweler
+# DO NOT EDIT THIS FILE DIRECTLY
+# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = %q{honeypot-captcha}
+ s.version = "0.0.1"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["curtis"]
+ s.date = %q{2010-04-09}
+ s.description = %q{A simple way to add honeypot captchas to Rails forms}
+ s.email = %q{curtis@flatterline.com}
+ s.extra_rdoc_files = [
+ "LICENSE",
+ "README.markdown"
+ ]
+ s.files = [
+ ".document",
+ ".gitignore",
+ "LICENSE",
+ "README.markdown",
+ "Rakefile",
+ "VERSION",
+ "honeypot-captcha.gemspec",
+ "lib/honeypot-captcha.rb",
+ "lib/honeypot-captcha/form_tag_helper.rb"
+ ]
+ s.homepage = %q{http://github.com/curtis/honeypot-captcha}
+ s.rdoc_options = ["--charset=UTF-8"]
+ s.require_paths = ["lib"]
+ s.rubygems_version = %q{1.3.5}
+ s.summary = %q{A simple way to add honeypot captchas to Rails forms}
+
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
+ else
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
+ end
+ else
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
+ end
+end
+
@@ -0,0 +1,23 @@
+require 'honeypot-captcha/form_tag_helper'
+
+module HoneypotCaptcha
+ module SpamProtection
+ def honeypot_fields
+ [:a_comment_body]
+ end
+
+ def protect_from_spam
+ head :ok if honeypot_fields.any? { |f| !params[f].blank? }
+ end
+
+ def self.included(base) # :nodoc:
+ base.send :helper_method, :honeypot_fields
+
+ if base.respond_to? :before_filter
+ base.send :prepend_before_filter, :protect_from_spam, :only => [:create, :update]
+ end
+ end
+ end
+end
+
+ActionController::Base.send(:include, HoneypotCaptcha::SpamProtection) if defined?(ActionController::Base)
@@ -0,0 +1,33 @@
+# Override the form_tag helper to add honeypot spam protection to forms.
+module ActionView
+ module Helpers
+ module FormTagHelper
+ def form_tag_with_honeypot(url_for_options = {}, options = {}, *parameters_for_url, &block)
+ honeypot = options.delete(:honeypot)
+ html = form_tag_without_honeypot(url_for_options, options, *parameters_for_url, &block)
+ if honeypot
+ if block_given?
+ html.insert(html.index('</form>'), honey_pot_captcha)
+ else
+ html += honey_pot_captcha
+ end
+ end
+ html
+ end
+ alias_method_chain :form_tag, :honeypot
+
+ private
+
+ def honey_pot_captcha
+ html_ids = []
+ honeypot_fields.collect do |f|
+ html_ids << (html_id = "#{f}_hp_#{Time.now.to_i}")
+ content_tag(:div, send([:text_field_tag, :text_area_tag][rand(2)], f), :id => html_id)
+ end.join +
+ content_tag(:style, :type => 'text/css', :media => 'screen') do
+ "#{html_ids.map { |i| "##{i}" }.join(', ')} { display:none; }"
+ end
+ end
+ end
+ end
+end
@@ -1,7 +0,0 @@
-require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
-
-describe "HoneypotCaptcha" do
- it "fails" do
- fail "hey buddy, you should probably rename this file and start specing for real"
- end
-end
View
@@ -1 +0,0 @@
---color
View
@@ -1,9 +0,0 @@
-$LOAD_PATH.unshift(File.dirname(__FILE__))
-$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-require 'honeypot-captcha'
-require 'spec'
-require 'spec/autorun'
-
-Spec::Runner.configure do |config|
-
-end

0 comments on commit 066aca7

Please sign in to comment.