Skip to content

Commit

Permalink
add visual_honeypots option; controller method with more options; mor…
Browse files Browse the repository at this point in the history
…e specs
  • Loading branch information
markets committed Sep 24, 2014
1 parent ef9bd5c commit b688246
Show file tree
Hide file tree
Showing 45 changed files with 502 additions and 25 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.bundle
pkg
.rvmrc
Gemfile.lock
Gemfile.lock
spec/dummy/log/*.log
spec/dummy/tmp/
3 changes: 1 addition & 2 deletions invisible_captcha.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ Gem::Specification.new do |spec|

spec.add_dependency 'rails'

spec.add_development_dependency 'debugger'
spec.add_development_dependency 'rspec', '~> 3.1'
spec.add_development_dependency 'rspec-rails', '~> 3.1'
end

5 changes: 4 additions & 1 deletion lib/invisible_captcha.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

module InvisibleCaptcha
class << self
attr_accessor :sentence_for_humans, :error_message, :fake_fields
attr_accessor :sentence_for_humans, :error_message, :fake_fields, :visual_honeypots

def init!
# Default sentence for humans if text field is visible
Expand All @@ -23,6 +23,9 @@ def init!

# Default fake fields for controller based workflow
self.fake_fields = ['foo_id', 'bar_id', 'baz_id']

# Enable it to make honeypots visibles
self.visual_honeypots = false
end

# InvisibleCaptcha.setup do |ic|
Expand Down
23 changes: 16 additions & 7 deletions lib/invisible_captcha/controller_ext.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
module InvisibleCaptcha
module ControllerExt
module ClassMethods
def invisible_captcha(options = {}, &block)
def invisible_captcha(options = {})
before_filter(options) do
check_invisible_captcha
detect_spam(options)
end
end
end

def check_invisible_captcha
head 200 if invisible_captcha?
def detect_spam(options = {})
if invisible_captcha?(options)
on_spam
end
end

def on_spam
head(200)
end

def invisible_captcha?(fake_resource = nil, fake_field = nil)
if fake_resource && fake_field
return true if params[fake_resource][fake_field].present?
def invisible_captcha?(options = {})
honeypot = options[:honeypot]
resource = options[:resource] || controller_name.singularize

if honeypot
return true if params[resource][honeypot].present?
else
InvisibleCaptcha.fake_fields.each do |field|
return true if params[field].present?
Expand Down
4 changes: 2 additions & 2 deletions lib/invisible_captcha/form_helpers.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module InvisibleCaptcha
module FormHelpers
def invisible_captcha(method)
@template.invisible_captcha(self.object_name, method)
def invisible_captcha(honeypot)
@template.invisible_captcha(self.object_name, honeypot)
end
end
end
4 changes: 2 additions & 2 deletions lib/invisible_captcha/validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ def validate_each(record, attribute, value)

private

def invisible_captcha?(object, attribute)
object.send(attribute).present?
def invisible_captcha?(object, honeypot)
object.send(honeypot).present?
end
end
end
8 changes: 4 additions & 4 deletions lib/invisible_captcha/view_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ def invisible_captcha(resource = nil, method = nil)
private

def build_invisible_captcha(resource = nil, method = nil)
resource = resource ? resource.to_s : InvisibleCaptcha.fake_field
label = InvisibleCaptcha.sentence_for_humans
html_id = generate_html_id(resource)
resource = resource ? resource.to_s : InvisibleCaptcha.fake_field
label = InvisibleCaptcha.sentence_for_humans
html_id = generate_html_id(resource)

content_tag(:div, :id => html_id) do
insert_inline_css(html_id) +
Expand All @@ -24,7 +24,7 @@ def generate_html_id(resource)

def insert_inline_css(container_id)
content_tag(:style, :type => 'text/css', :media => 'screen', :scoped => 'scoped') do
"##{container_id} { display:none; }"
"##{container_id} { display:none; }" unless InvisibleCaptcha.visual_honeypots
end
end

Expand Down
19 changes: 19 additions & 0 deletions spec/controllers_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require 'spec_helper'

describe InvisibleCaptcha::ControllerExt, type: :controller do
render_views

before { @controller = TopicsController.new }

it 'with spam' do
post :create, topic: { subtitle: 'foo' }

expect(response.body).to be_blank
end

it 'with no spam' do
post :create, topic: { title: 'foo' }

expect(response.body).to be_present
end
end
3 changes: 3 additions & 0 deletions spec/dummy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Dummy App

Dummy Rails Application to test `Invisible Captcha`.
7 changes: 7 additions & 0 deletions spec/dummy/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require File.expand_path('../config/application', __FILE__)

Dummy::Application.load_tasks
15 changes: 15 additions & 0 deletions spec/dummy/app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery_ujs
//= require_tree .
13 changes: 13 additions & 0 deletions spec/dummy/app/assets/stylesheets/application.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the top of the
* compiled file, but it's generally better to create a new file per style scope.
*
*= require_self
*= require_tree .
*/
3 changes: 3 additions & 0 deletions spec/dummy/app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class ApplicationController < ActionController::Base
protect_from_forgery
end
17 changes: 17 additions & 0 deletions spec/dummy/app/controllers/topics_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class TopicsController < ApplicationController
invisible_captcha honeypot: :subtitle, only: :create

def new
@topic = Topic.new
end

def create
@topic = Topic.new(params[:topic])

if @topic.valid?
redirect_to new_topic_path, notice: 'OK!'
else
render action: 'new'
end
end
end
2 changes: 2 additions & 0 deletions spec/dummy/app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module ApplicationHelper
end
Empty file added spec/dummy/app/mailers/.gitkeep
Empty file.
Empty file added spec/dummy/app/models/.gitkeep
Empty file.
18 changes: 18 additions & 0 deletions spec/dummy/app/models/topic.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class Topic
include ActiveModel::Validations
include ActiveModel::Conversion

attr_accessor :title, :body, :subtitle

validates :subtitle, invisible_captcha: true

def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end

def persisted?
false
end
end
14 changes: 14 additions & 0 deletions spec/dummy/app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>Dummy</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>

<%= yield %>

</body>
</html>
18 changes: 18 additions & 0 deletions spec/dummy/app/views/topics/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<h1>New topic</h1>

<%= form_for(@topic) do |f| %>
<%= f.invisible_captcha :subtitle %>
<%#= invisible_captcha %>

<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
4 changes: 4 additions & 0 deletions spec/dummy/config.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# This file is used by Rack-based servers to start the application.

require ::File.expand_path('../config/environment', __FILE__)
run Dummy::Application
20 changes: 20 additions & 0 deletions spec/dummy/config/application.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require File.expand_path('../boot', __FILE__)

require 'action_controller/railtie'
require 'action_view/railtie'
require 'action_mailer/railtie'
require 'active_model/railtie'

Bundler.require(*Rails.groups)

require 'invisible_captcha'

module Dummy
class Application < Rails::Application
config.encoding = 'utf-8'
config.filter_parameters += [:password]
config.assets.enabled = true
config.assets.version = '1.0'
end
end

5 changes: 5 additions & 0 deletions spec/dummy/config/boot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)

require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
$LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
5 changes: 5 additions & 0 deletions spec/dummy/config/environment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Load the rails application
require File.expand_path('../application', __FILE__)

# Initialize the rails application
Dummy::Application.initialize!
30 changes: 30 additions & 0 deletions spec/dummy/config/environments/development.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Dummy::Application.configure do
# Settings specified here will take precedence over those in config/application.rb

# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false

# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true

# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false

# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false

# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log

# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin

# Do not compress assets
config.assets.compress = false

# Expands the lines which load the assets
config.assets.debug = true
end
67 changes: 67 additions & 0 deletions spec/dummy/config/environments/production.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
Dummy::Application.configure do
# Settings specified here will take precedence over those in config/application.rb

# Code is not reloaded between requests
config.cache_classes = true

# Full error reports are disabled and caching is turned on
config.consider_all_requests_local = false
config.action_controller.perform_caching = true

# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_assets = false

# Compress JavaScripts and CSS
config.assets.compress = true

# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false

# Generate digests for assets URLs
config.assets.digest = true

# Defaults to nil and saved in location specified by config.assets.prefix
# config.assets.manifest = YOUR_PATH

# Specifies the header that your server uses for sending files
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx

# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true

# See everything in the log (default is :info)
# config.log_level = :debug

# Prepend all log lines with the following tags
# config.log_tags = [ :subdomain, :uuid ]

# Use a different logger for distributed setups
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)

# Use a different cache store in production
# config.cache_store = :mem_cache_store

# Enable serving of images, stylesheets, and JavaScripts from an asset server
# config.action_controller.asset_host = "http://assets.example.com"

# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
# config.assets.precompile += %w( search.js )

# Disable delivery errors, bad email addresses will be ignored
# config.action_mailer.raise_delivery_errors = false

# Enable threaded mode
# config.threadsafe!

# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation can not be found)
config.i18n.fallbacks = true

# Send deprecation notices to registered listeners
config.active_support.deprecation = :notify

# Log the query plan for queries taking more than this (works
# with SQLite, MySQL, and PostgreSQL)
# config.active_record.auto_explain_threshold_in_seconds = 0.5
end
Loading

0 comments on commit b688246

Please sign in to comment.