invisible-captcha-0.12.2/0000755000175000017500000000000013541745065015731 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/0000755000175000017500000000000013541745065016663 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/spec_helper.rb0000644000175000017500000000141113541745065021476 0ustar utkarsh2102utkarsh2102ENV['RAILS_ENV'] = 'test' require File.expand_path("../dummy/config/environment.rb", __FILE__) require 'rspec/rails' require 'invisible_captcha' RSpec.configure do |config| config.disable_monkey_patching! config.order = :random config.expect_with :rspec config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end end # Rails 4.2 call `initialize` inside `recycle!`. However Ruby 2.6 doesn't allow calling `initialize` twice. # More info: https://github.com/rails/rails/issues/34790 if RUBY_VERSION >= "2.6.0" && Rails.version < "5" module ActionController class TestResponse < ActionDispatch::TestResponse def recycle! @mon_mutex_owner_object_id = nil @mon_mutex = nil initialize end end end end invisible-captcha-0.12.2/spec/invisible_captcha_spec.rb0000644000175000017500000000365013541745065023675 0ustar utkarsh2102utkarsh2102RSpec.describe InvisibleCaptcha do it 'initialize with defaults' do InvisibleCaptcha.init! expect(InvisibleCaptcha.sentence_for_humans).to eq('If you are a human, ignore this field') expect(InvisibleCaptcha.timestamp_threshold).to eq(4.seconds) expect(InvisibleCaptcha.timestamp_error_message).to eq('Sorry, that was too quick! Please resubmit.') expect(InvisibleCaptcha.honeypots).to be_an_instance_of(Array) expect(InvisibleCaptcha.injectable_styles).to eq(false) end it 'allow setup via block' do InvisibleCaptcha.setup do |ic| ic.sentence_for_humans = 'Another sentence' end expect(InvisibleCaptcha.sentence_for_humans).to eq('Another sentence') end it 'It uses I18n when available' do InvisibleCaptcha.init! I18n.available_locales = [:en, :fr] I18n.backend.store_translations(:en, 'invisible_captcha' => { 'sentence_for_humans' => "Can't touch this", 'timestamp_error_message' => 'Fast and furious' }) I18n.backend.store_translations(:fr, 'invisible_captcha' => { 'sentence_for_humans' => 'Ne touchez pas', 'timestamp_error_message' => 'Plus doucement SVP' }) I18n.locale = :en expect(InvisibleCaptcha.sentence_for_humans).to eq("Can't touch this") expect(InvisibleCaptcha.timestamp_error_message).to eq('Fast and furious') I18n.locale = :fr expect(InvisibleCaptcha.sentence_for_humans).to eq('Ne touchez pas') expect(InvisibleCaptcha.timestamp_error_message).to eq('Plus doucement SVP') I18n.backend.reload! expect(InvisibleCaptcha.sentence_for_humans).to eq('If you are a human, ignore this field') expect(InvisibleCaptcha.timestamp_error_message).to eq('Sorry, that was too quick! Please resubmit.') end end invisible-captcha-0.12.2/spec/dummy/0000755000175000017500000000000013541745065020016 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/lib/0000755000175000017500000000000013541745065020564 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/lib/assets/0000755000175000017500000000000013541745065022066 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/lib/assets/.gitkeep0000644000175000017500000000000013541745065023505 0ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/config/0000755000175000017500000000000013541745065021263 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/config/locales/0000755000175000017500000000000013541745065022705 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/config/locales/en.yml0000644000175000017500000000117213541745065024033 0ustar utkarsh2102utkarsh2102# Files in the config/locales directory are used for internationalization # and are automatically loaded by Rails. If you want to use locales other # than English, add the necessary files in this directory. # # To use the locales, use `I18n.t`: # # I18n.t 'hello' # # In views, this is aliased to just `t`: # # <%= t('hello') %> # # To use a different locale, set it with `I18n.locale`: # # I18n.locale = :es # # This would use the information in config/locales/es.yml. # # To learn more, please read the Rails Internationalization guide # available at http://guides.rubyonrails.org/i18n.html. en: hello: "Hello world" invisible-captcha-0.12.2/spec/dummy/config/application.rb0000644000175000017500000000240013541745065024107 0ustar utkarsh2102utkarsh2102require File.expand_path('../boot', __FILE__) require 'action_controller/railtie' require 'action_view/railtie' require 'action_mailer/railtie' require 'active_model/railtie' require 'sprockets/railtie' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) require 'invisible_captcha' module Dummy class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de # Do not swallow errors in after_commit/after_rollback callbacks. # config.active_record.raise_in_transactional_callbacks = true end end invisible-captcha-0.12.2/spec/dummy/config/routes.rb0000644000175000017500000000023213541745065023126 0ustar utkarsh2102utkarsh2102Rails.application.routes.draw do resources :topics do post :publish, on: :member post :copy, on: :collection end root to: 'topics#new' end invisible-captcha-0.12.2/spec/dummy/config/initializers/0000755000175000017500000000000013541745065023771 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/config/initializers/inflections.rb0000644000175000017500000000120713541745065026633 0ustar utkarsh2102utkarsh2102# Be sure to restart your server when you modify this file. # Add new inflection rules using the following format. Inflections # are locale specific, and you may define rules for as many different # locales as you wish. All of these examples are active by default: # ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.plural /^(ox)$/i, '\1en' # inflect.singular /^(ox)en/i, '\1' # inflect.irregular 'person', 'people' # inflect.uncountable %w( fish sheep ) # end # These inflection rules are supported but not enabled by default: # ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.acronym 'RESTful' # end invisible-captcha-0.12.2/spec/dummy/config/initializers/wrap_parameters.rb0000644000175000017500000000100513541745065027506 0ustar utkarsh2102utkarsh2102# Be sure to restart your server when you modify this file. # This file contains settings for ActionController::ParamsWrapper which # is enabled by default. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do wrap_parameters format: [:json] if respond_to?(:wrap_parameters) end # To enable root element in JSON for ActiveRecord objects. # ActiveSupport.on_load(:active_record) do # self.include_root_in_json = true # end invisible-captcha-0.12.2/spec/dummy/config/initializers/backtrace_silencers.rb0000644000175000017500000000062413541745065030306 0ustar utkarsh2102utkarsh2102# Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. # Rails.backtrace_cleaner.remove_silencers! invisible-captcha-0.12.2/spec/dummy/config/initializers/secret_token.rb0000644000175000017500000000076013541745065027006 0ustar utkarsh2102utkarsh2102# Be sure to restart your server when you modify this file. # Your secret key for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. Dummy::Application.config.secret_token = '99a354dfaace29d4d6daae4be11b63c13799e60ddff44a5880b12bf2e551de5daef2688495da1475131b5b0a85e57c4303a6b72834edc8a1b51a8c94d9949d59' invisible-captcha-0.12.2/spec/dummy/config/initializers/cookies_serializer.rb0000644000175000017500000000020413541745065030177 0ustar utkarsh2102utkarsh2102# Be sure to restart your server when you modify this file. Rails.application.config.action_dispatch.cookies_serializer = :marshal invisible-captcha-0.12.2/spec/dummy/config/initializers/mime_types.rb0000644000175000017500000000023413541745065026470 0ustar utkarsh2102utkarsh2102# Be sure to restart your server when you modify this file. # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf invisible-captcha-0.12.2/spec/dummy/config/initializers/session_store.rb0000644000175000017500000000021113541745065027207 0ustar utkarsh2102utkarsh2102# Be sure to restart your server when you modify this file. Rails.application.config.session_store :cookie_store, key: '_dummy_session' invisible-captcha-0.12.2/spec/dummy/config/initializers/filter_parameter_logging.rb0000644000175000017500000000030213541745065031344 0ustar utkarsh2102utkarsh2102# Be sure to restart your server when you modify this file. # Configure sensitive parameters which will be filtered from the log file. Rails.application.config.filter_parameters += [:password] invisible-captcha-0.12.2/spec/dummy/config/environments/0000755000175000017500000000000013541745065024012 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/config/environments/production.rb0000644000175000017500000000677213541745065026541 0ustar utkarsh2102utkarsh2102Rails.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 # Eager load code on boot. This eager loads most of Rails and # your application in memory, allowing both threaded web servers # and those relying on copy on write to perform better. # Rake tasks automatically ignore this option for performance. config.eager_load = true # Full error reports are disabled and caching is turned on. config.consider_all_requests_local = false config.action_controller.perform_caching = true # Disable serving static files from the `/public` folder by default since # Apache or NGINX already handles this. config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress JavaScripts and CSS. config.assets.js_compressor = :uglifier # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.action_controller.asset_host = 'http://assets.example.com' # 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 # Mount Action Cable outside main process or domain # config.action_cable.mount_path = nil # config.action_cable.url = 'wss://example.com/cable' # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true # Use the lowest log level to ensure availability of diagnostic information # when problems arise. config.log_level = :debug # Prepend all log lines with the following tags. config.log_tags = [ :request_id ] # Use a different cache store in production. # config.cache_store = :mem_cache_store # Use a real queuing backend for Active Job (and separate queues per environment) # config.active_job.queue_adapter = :resque # config.active_job.queue_name_prefix = "dummy_#{Rails.env}" config.action_mailer.perform_caching = false # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new # Use a different logger for distributed setups. # require 'syslog/logger' # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') if ENV["RAILS_LOG_TO_STDOUT"].present? logger = ActiveSupport::Logger.new(STDOUT) logger.formatter = config.log_formatter config.logger = ActiveSupport::TaggedLogging.new(logger) end # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false end invisible-captcha-0.12.2/spec/dummy/config/environments/test.rb0000644000175000017500000000335213541745065025321 0ustar utkarsh2102utkarsh2102Dummy::Application.configure do # Settings specified here will take precedence over those in config/application.rb. # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! config.cache_classes = true # Do not eager load code on boot. This avoids loading your whole application # just for the purpose of running a single test. If you are using a tool that # preloads Rails for running tests, you may have to set it to true. config.eager_load = false # Disable serving static files from the `/public` folder by default since # Apache or NGINX already handles this. if Rails.version >= "5.0.0" config.public_file_server.enabled = true config.public_file_server.headers = {'Cache-Control' => 'public, max-age=3600'} else config.serve_static_files = true config.static_cache_control = "public, max-age=3600" end # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false # Raise exceptions instead of rendering exception templates. config.action_dispatch.show_exceptions = false # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr endinvisible-captcha-0.12.2/spec/dummy/config/environments/development.rb0000644000175000017500000000317013541745065026662 0ustar utkarsh2102utkarsh2102Dummy::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 # Do not eager load code on boot. config.eager_load = false # 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 # Raise an error on page load if there are pending migrations. # config.active_record.migration_error = :page_load # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. # config.assets.debug = true # Asset digests allow you to set far-future HTTP expiration dates on all assets, # yet still be able to expire them through the digest params. # config.assets.digest = true # quiet assets config.assets.quiet = true # Adds additional error checking when serving assets at runtime. # Checks for improperly declared sprockets dependencies. # Raises helpful error messages. # config.assets.raise_runtime_errors = true # Raises error for missing translations # config.action_view.raise_on_missing_translations = true end invisible-captcha-0.12.2/spec/dummy/config/boot.rb0000644000175000017500000000020013541745065022543 0ustar utkarsh2102utkarsh2102ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) require 'bundler/setup' # Set up gems listed in the Gemfile. invisible-captcha-0.12.2/spec/dummy/config/secrets.yml0000644000175000017500000000170413541745065023460 0ustar utkarsh2102utkarsh2102# Be sure to restart your server when you modify this file. # Your secret key is used for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. # You can use `rake secret` to generate a secure secret key. # Make sure the secrets in this file are kept private # if you're sharing your code publicly. development: secret_key_base: d55ed9a6ec6fc0b93d2404994c8632220ab5835d77ccbd52760c6fc4b9e0c83f87d78d9c2b66d366a698933feeac81efc445b29bad22c9f267ebdadbc5aebbd4 test: secret_key_base: 5df5772ea2c76236d1444a2e7a491c9f99f9bc96770b6b52e995555ea7a70b2bd3a3d0a45bbe7d32bf1a0eb450db7e32a838e6aa17c494b464ff381bb4bf9910 # Do not keep production secrets in the repository, # instead read values from the environment. production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> invisible-captcha-0.12.2/spec/dummy/config/environment.rb0000644000175000017500000000020013541745065024144 0ustar utkarsh2102utkarsh2102# Load the Rails application. require_relative 'application' # Initialize the Rails application. Rails.application.initialize! invisible-captcha-0.12.2/spec/dummy/Rakefile0000644000175000017500000000041613541745065021464 0ustar utkarsh2102utkarsh2102#!/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 invisible-captcha-0.12.2/spec/dummy/app/0000755000175000017500000000000013541745065020576 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/controllers/0000755000175000017500000000000013541745065023144 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/controllers/application_controller.rb0000644000175000017500000000012013541745065030230 0ustar utkarsh2102utkarsh2102class ApplicationController < ActionController::Base protect_from_forgery end invisible-captcha-0.12.2/spec/dummy/app/controllers/topics_controller.rb0000644000175000017500000000220313541745065027232 0ustar utkarsh2102utkarsh2102class TopicsController < ApplicationController invisible_captcha honeypot: :subtitle, only: :create invisible_captcha honeypot: :subtitle, only: :update, on_spam: :custom_callback, on_timestamp_spam: :custom_timestamp_callback invisible_captcha honeypot: :subtitle, only: :publish, timestamp_threshold: 2 invisible_captcha honeypot: :subtitle, only: :copy, timestamp_enabled: false def index redirect_to new_topic_path end def new @topic = Topic.new end def create @topic = Topic.new(params[:topic]) if @topic.valid? redirect_to new_topic_path(context: params[:context]), notice: 'Topic valid!' else render action: 'new' end end def update end def publish redirect_to new_topic_path end def copy @topic = Topic.new(params[:topic]) if @topic.valid? redirect_to new_topic_path(context: params[:context]), notice: 'Success!' else render action: 'new' end end private def custom_callback redirect_to new_topic_path end def custom_timestamp_callback head(204) end end invisible-captcha-0.12.2/spec/dummy/app/models/0000755000175000017500000000000013541745065022061 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/models/topic.rb0000644000175000017500000000063113541745065023524 0ustar utkarsh2102utkarsh2102class Topic include ActiveModel::Validations include ActiveModel::Conversion attr_accessor :title, :author, :body, :subtitle validates :title, length: { minimum: 5 } validates :author, presence: true validates :body, length: { minimum: 10 } def initialize(attributes = {}) attributes.each do |name, value| send("#{name}=", value) end end def persisted? false end end invisible-captcha-0.12.2/spec/dummy/app/mailers/0000755000175000017500000000000013541745065022232 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/mailers/.gitkeep0000644000175000017500000000000013541745065023651 0ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/helpers/0000755000175000017500000000000013541745065022240 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/helpers/application_helper.rb0000644000175000017500000000003513541745065026425 0ustar utkarsh2102utkarsh2102module ApplicationHelper end invisible-captcha-0.12.2/spec/dummy/app/views/0000755000175000017500000000000013541745065021733 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/views/layouts/0000755000175000017500000000000013541745065023433 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/views/layouts/application.html.erb0000644000175000017500000000134113541745065027372 0ustar utkarsh2102utkarsh2102 Dummy <%= stylesheet_link_tag "application", :media => "all" %> <%= javascript_include_tag "application" %> <%= csrf_meta_tags %> <%= invisible_captcha_styles %>

InvisibleCaptcha v<%= InvisibleCaptcha::VERSION %> - Demo

<%= link_to "Default settings", new_topic_path %> | <%= link_to "With visual honeypots", new_topic_path(context: "visual_honeypots") %> | <%= link_to "With timestamp disabled", new_topic_path(context: "timestamp_disabled") %>

<% flash.each do |key, value| %> <% end %> <%= yield %> invisible-captcha-0.12.2/spec/dummy/app/views/topics/0000755000175000017500000000000013541745065023234 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/views/topics/new.html.erb0000644000175000017500000000201313541745065025456 0ustar utkarsh2102utkarsh2102<% if @topic.errors.any? %>
<%= pluralize(@topic.errors.count, "error") %> prohibited this record from being saved:
<% end %> <%= form_for(@topic, url: { action: params[:context] == 'timestamp_disabled' ? :copy : :create }) do |f| %> <%= hidden_field_tag :context, params[:context] %> <% if params[:context] && params[:context] == 'visual_honeypots' %> <%= f.invisible_captcha :subtitle, visual_honeypots: true %> <% else %> <%= f.invisible_captcha :subtitle %> <% end %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :author %>
<%= f.text_field :author %>
<%= f.label :body %>
<%= f.text_area :body, rows: 10, cols: 40 %>
<%= f.button 'Save' %>
<% end %> invisible-captcha-0.12.2/spec/dummy/app/assets/0000755000175000017500000000000013541745065022100 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/assets/stylesheets/0000755000175000017500000000000013541745065024454 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/assets/stylesheets/application.css0000644000175000017500000000054713541745065027477 0ustar utkarsh2102utkarsh2102body { font-family: Arial, Helvetica, sans-serif; background-color: #ccc; margin: 2em; } h1 { border-bottom: 3px solid; } input, textarea { border: 0; margin-bottom: 1.5em; } input { height: 2em; } button { background-color: #f0f0f0; border-radius: 0.25em; height: 3em; width: 10em; font-size: 1em; } .errors { color: darkred; }invisible-captcha-0.12.2/spec/dummy/app/assets/javascripts/0000755000175000017500000000000013541745065024431 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/app/assets/javascripts/application.js0000644000175000017500000000005213541745065027267 0ustar utkarsh2102utkarsh2102console.log('Hi from Invisible Captcha!');invisible-captcha-0.12.2/spec/dummy/bin/0000755000175000017500000000000013541745065020566 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/bin/rails0000755000175000017500000000022113541745065021621 0ustar utkarsh2102utkarsh2102#!/usr/bin/env ruby APP_PATH = File.expand_path('../../config/application', __FILE__) require_relative '../config/boot' require 'rails/commands' invisible-captcha-0.12.2/spec/dummy/bin/rake0000755000175000017500000000013213541745065021432 0ustar utkarsh2102utkarsh2102#!/usr/bin/env ruby require_relative '../config/boot' require 'rake' Rake.application.run invisible-captcha-0.12.2/spec/dummy/bin/bundle0000755000175000017500000000020113541745065021756 0ustar utkarsh2102utkarsh2102#!/usr/bin/env ruby ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) load Gem.bin_path('bundler', 'bundle') invisible-captcha-0.12.2/spec/dummy/bin/setup0000755000175000017500000000144513541745065021660 0ustar utkarsh2102utkarsh2102#!/usr/bin/env ruby require 'pathname' # path to your application root. APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) Dir.chdir APP_ROOT do # This script is a starting point to setup your application. # Add necessary setup steps to this file: puts "== Installing dependencies ==" system "gem install bundler --conservative" system "bundle check || bundle install" # puts "\n== Copying sample files ==" # unless File.exist?("config/database.yml") # system "cp config/database.yml.sample config/database.yml" # end puts "\n== Preparing database ==" system "bin/rake db:setup" puts "\n== Removing old logs and tempfiles ==" system "rm -f log/*" system "rm -rf tmp/cache" puts "\n== Restarting application server ==" system "touch tmp/restart.txt" end invisible-captcha-0.12.2/spec/dummy/README.md0000644000175000017500000000052013541745065021272 0ustar utkarsh2102utkarsh2102# Dummy App Dummy Rails Application to test `Invisible Captcha`. It's also used as a demo application to show `Invisible Captcha` in action. You can run the app by using the following command, from the root of the project: > bundle exec rake web [« Back to Docs](https://github.com/markets/invisible_captcha#invisible-captcha) invisible-captcha-0.12.2/spec/dummy/public/0000755000175000017500000000000013541745065021274 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/public/422.html0000644000175000017500000000130713541745065022472 0ustar utkarsh2102utkarsh2102 The change you wanted was rejected (422)

The change you wanted was rejected.

Maybe you tried to change something you didn't have access to.

invisible-captcha-0.12.2/spec/dummy/public/500.html0000644000175000017500000000120313541745065022462 0ustar utkarsh2102utkarsh2102 We're sorry, but something went wrong (500)

We're sorry, but something went wrong.

invisible-captcha-0.12.2/spec/dummy/public/404.html0000644000175000017500000000133013541745065022466 0ustar utkarsh2102utkarsh2102 The page you were looking for doesn't exist (404)

The page you were looking for doesn't exist.

You may have mistyped the address or the page may have moved.

invisible-captcha-0.12.2/spec/dummy/public/favicon.ico0000644000175000017500000000000013541745065023403 0ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/config.ru0000644000175000017500000000023313541745065021631 0ustar utkarsh2102utkarsh2102# This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) run Dummy::Application invisible-captcha-0.12.2/spec/dummy/log/0000755000175000017500000000000013541745065020577 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/dummy/log/.gitkeep0000644000175000017500000000000013541745065022216 0ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/spec/controllers_spec.rb0000644000175000017500000001022313541745065022566 0ustar utkarsh2102utkarsh2102RSpec.describe InvisibleCaptcha::ControllerExt, type: :controller do render_views def switchable_post(action, params = {}) if ::Rails::VERSION::STRING > '5' post action, params: params else post action, params end end def switchable_put(action, params = {}) if ::Rails::VERSION::STRING > '5' put action, params: params else put action, params end end before(:each) do @controller = TopicsController.new request.env['HTTP_REFERER'] = 'http://test.host/topics' InvisibleCaptcha.init! InvisibleCaptcha.timestamp_threshold = 1 end context 'without invisible_captcha_timestamp in session' do it 'fails like if it was submitted too fast' do switchable_post :create, topic: { title: 'foo' } expect(response).to redirect_to 'http://test.host/topics' expect(flash[:error]).to eq(InvisibleCaptcha.timestamp_error_message) end it 'passes if disabled at action level' do switchable_post :copy, topic: { title: 'foo' } expect(flash[:error]).not_to be_present expect(response.body).to be_present end it 'passes if disabled at app level' do InvisibleCaptcha.timestamp_enabled = false switchable_post :create, topic: { title: 'foo' } expect(flash[:error]).not_to be_present expect(response.body).to be_present end end context 'submission timestamp_threshold' do before(:each) do session[:invisible_captcha_timestamp] = Time.zone.now.iso8601 end it 'fails if submission before timestamp_threshold' do switchable_post :create, topic: { title: 'foo' } expect(response).to redirect_to 'http://test.host/topics' expect(flash[:error]).to eq(InvisibleCaptcha.timestamp_error_message) # Make sure session is cleared expect(session[:invisible_captcha_timestamp]).to be_nil end it 'allows a custom on_timestamp_spam callback' do switchable_put :update, id: 1, topic: { title: 'bar' } expect(response.status).to eq(204) end it 'allows a new timestamp to be set in the on_timestamp_spam callback' do @controller.singleton_class.class_eval do def custom_timestamp_callback session[:invisible_captcha_timestamp] = 2.seconds.from_now(Time.zone.now).iso8601 head(204) end end expect { switchable_put :update, id: 1, topic: { title: 'bar' } } .to change { session[:invisible_captcha_timestamp] } .to be_present end context 'successful submissions' do it 'passes if submission on or after timestamp_threshold' do sleep InvisibleCaptcha.timestamp_threshold switchable_post :create, topic: { title: 'foobar', author: 'author', body: 'body that passes validation' } expect(flash[:error]).not_to be_present expect(response.body).to be_present # Make sure session is cleared expect(session[:invisible_captcha_timestamp]).to be_nil end it 'allow to set a custom timestamp_threshold per action' do sleep 2 # custom threshold switchable_post :publish, id: 1 expect(flash[:error]).not_to be_present expect(response.body).to be_present end end end context 'honeypot attribute' do before(:each) do session[:invisible_captcha_timestamp] = Time.zone.now.iso8601 # Wait for valid submission sleep InvisibleCaptcha.timestamp_threshold end it 'fails with spam' do switchable_post :create, topic: { subtitle: 'foo' } expect(response.body).to be_blank end it 'passes with no spam' do switchable_post :create, topic: { title: 'foo' } expect(response.body).to be_present end it 'allow a custom on_spam callback' do switchable_put :update, id: 1, topic: { subtitle: 'foo' } expect(response.body).to redirect_to(new_topic_path) end it 'honeypot is removed from params if you use a custom honeypot' do switchable_post :create, topic: { title: 'foo', subtitle: '' } expect(flash[:error]).not_to be_present expect(@controller.params[:topic].key?(:subtitle)).to eq(false) end end end invisible-captcha-0.12.2/spec/view_helpers_spec.rb0000644000175000017500000000467713541745065022734 0ustar utkarsh2102utkarsh2102RSpec.describe InvisibleCaptcha::ViewHelpers, type: :helper do before(:each) do allow(Time.zone).to receive(:now).and_return(Time.zone.parse('Feb 19 1986')) allow(InvisibleCaptcha).to receive(:css_strategy).and_return("display:none;") # to test content_for and provide @view_flow = ActionView::OutputFlow.new InvisibleCaptcha.init! end it 'with no arguments' do InvisibleCaptcha.honeypots = [:foo_id] expect(invisible_captcha).to match(/name="foo_id"/) end it 'with specific honeypot' do expect(invisible_captcha(:subtitle)).to match(/name="subtitle"/) end it 'with specific honeypot and scope' do expect(invisible_captcha(:subtitle, :topic)).to match(/name="topic\[subtitle\]"/) end it 'with custom html options' do expect(invisible_captcha(:subtitle, :topic, { class: 'foo_class' })).to match(/class="foo_class"/) end it 'generated html + styles' do InvisibleCaptcha.honeypots = [:foo_id] output = invisible_captcha.gsub("\"", "'") regexp = %r{
.foo_id_\w* {display:none;}#{InvisibleCaptcha.sentence_for_humans}
} expect(output).to match(regexp) end context "honeypot visibilty" do it 'visible from defaults' do InvisibleCaptcha.visual_honeypots = true expect(invisible_captcha).not_to match(/display:none/) end it 'visible from given instance (default override)' do expect(invisible_captcha(visual_honeypots: true)).not_to match(/display:none/) end it 'invisible from given instance (default override)' do InvisibleCaptcha.visual_honeypots = true expect(invisible_captcha(visual_honeypots: false)).to match(/display:none/) end end it 'should set spam timestamp' do invisible_captcha expect(session[:invisible_captcha_timestamp]).to eq(Time.zone.now.iso8601) end context 'injectable_styles option' do it 'by default, render styles along with the honeypot' do expect(invisible_captcha).to match(/display:none/) expect(@view_flow.content[:invisible_captcha_styles]).to be_blank end it 'if injectable_styles is set, do not append styles inline' do InvisibleCaptcha.injectable_styles = true expect(invisible_captcha).not_to match(/display:none;/) expect(@view_flow.content[:invisible_captcha_styles]).to match(/display:none;/) end end end invisible-captcha-0.12.2/gemfiles/0000755000175000017500000000000013541745065017524 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/gemfiles/rails_3.2.gemfile0000644000175000017500000000016413541745065022553 0ustar utkarsh2102utkarsh2102# This file was generated by Appraisal source "https://rubygems.org" gem "rails", "~> 3.2.0" gemspec path: "../" invisible-captcha-0.12.2/gemfiles/rails_5.1.gemfile0000644000175000017500000000016413541745065022554 0ustar utkarsh2102utkarsh2102# This file was generated by Appraisal source "https://rubygems.org" gem "rails", "~> 5.1.0" gemspec path: "../" invisible-captcha-0.12.2/gemfiles/rails_5.2.gemfile0000644000175000017500000000016413541745065022555 0ustar utkarsh2102utkarsh2102# This file was generated by Appraisal source "https://rubygems.org" gem "rails", "~> 5.2.0" gemspec path: "../" invisible-captcha-0.12.2/gemfiles/rails_5.0.gemfile0000644000175000017500000000016413541745065022553 0ustar utkarsh2102utkarsh2102# This file was generated by Appraisal source "https://rubygems.org" gem "rails", "~> 5.0.0" gemspec path: "../" invisible-captcha-0.12.2/gemfiles/rails_4.2.gemfile0000644000175000017500000000016413541745065022554 0ustar utkarsh2102utkarsh2102# This file was generated by Appraisal source "https://rubygems.org" gem "rails", "~> 4.2.0" gemspec path: "../" invisible-captcha-0.12.2/gemfiles/rails_6.0.gemfile0000644000175000017500000000016413541745065022554 0ustar utkarsh2102utkarsh2102# This file was generated by Appraisal source "https://rubygems.org" gem "rails", "~> 6.0.0" gemspec path: "../" invisible-captcha-0.12.2/Appraisals0000644000175000017500000000051113541745065017750 0ustar utkarsh2102utkarsh2102appraise "rails-6.0" do gem "rails", "~> 6.0.0" end appraise "rails-5.2" do gem "rails", "~> 5.2.0" end appraise "rails-5.1" do gem "rails", "~> 5.1.0" end appraise "rails-5.0" do gem "rails", "~> 5.0.0" end appraise "rails-4.2" do gem "rails", "~> 4.2.0" end appraise "rails-3.2" do gem "rails", "~> 3.2.0" end invisible-captcha-0.12.2/.rspec0000644000175000017500000000006513541745065017047 0ustar utkarsh2102utkarsh2102--format documentation --color --require spec_helper invisible-captcha-0.12.2/LICENSE0000644000175000017500000000204613541745065016740 0ustar utkarsh2102utkarsh2102Copyright 2012-2017 Marc Anguera Insa 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 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. invisible-captcha-0.12.2/lib/0000755000175000017500000000000013541745065016477 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/lib/invisible_captcha/0000755000175000017500000000000013541745065022146 5ustar utkarsh2102utkarsh2102invisible-captcha-0.12.2/lib/invisible_captcha/form_helpers.rb0000644000175000017500000000026713541745065025165 0ustar utkarsh2102utkarsh2102module InvisibleCaptcha module FormHelpers def invisible_captcha(honeypot, options = {}) @template.invisible_captcha(honeypot, self.object_name, options) end end endinvisible-captcha-0.12.2/lib/invisible_captcha/view_helpers.rb0000644000175000017500000000455213541745065025175 0ustar utkarsh2102utkarsh2102module InvisibleCaptcha module ViewHelpers # Builds the honeypot html # # @param honeypot [Symbol] name of honeypot, ie: subtitle => input name: subtitle # @param scope [Symbol] name of honeypot scope, ie: topic => input name: topic[subtitle] # @param options [Hash] html_options for input and invisible_captcha options # # @return [String] the generated html def invisible_captcha(honeypot = nil, scope = nil, options = {}) if InvisibleCaptcha.timestamp_enabled session[:invisible_captcha_timestamp] = Time.zone.now.iso8601 end build_invisible_captcha(honeypot, scope, options) end def invisible_captcha_styles if content_for?(:invisible_captcha_styles) content_for(:invisible_captcha_styles) end end private def build_invisible_captcha(honeypot = nil, scope = nil, options = {}) if honeypot.is_a?(Hash) options = honeypot honeypot = nil end honeypot = honeypot ? honeypot.to_s : InvisibleCaptcha.get_honeypot label = options.delete(:sentence_for_humans) || InvisibleCaptcha.sentence_for_humans css_class = "#{honeypot}_#{Time.zone.now.to_i}" styles = visibility_css(css_class, options) provide(:invisible_captcha_styles) do styles end if InvisibleCaptcha.injectable_styles content_tag(:div, class: css_class) do concat styles unless InvisibleCaptcha.injectable_styles concat label_tag(build_label_name(honeypot, scope), label) concat text_field_tag(build_input_name(honeypot, scope), nil, default_honeypot_options.merge(options)) end end def visibility_css(css_class, options) visible = if options.key?(:visual_honeypots) options.delete(:visual_honeypots) else InvisibleCaptcha.visual_honeypots end return if visible content_tag(:style, media: 'screen') do ".#{css_class} {#{InvisibleCaptcha.css_strategy}}" end end def build_label_name(honeypot, scope = nil) if scope.present? "#{scope}_#{honeypot}" else honeypot end end def build_input_name(honeypot, scope = nil) if scope.present? "#{scope}[#{honeypot}]" else honeypot end end def default_honeypot_options { autocomplete: 'off', tabindex: -1 } end end end invisible-captcha-0.12.2/lib/invisible_captcha/version.rb0000644000175000017500000000006113541745065024155 0ustar utkarsh2102utkarsh2102module InvisibleCaptcha VERSION = "0.12.2" end invisible-captcha-0.12.2/lib/invisible_captcha/railtie.rb0000644000175000017500000000075213541745065024130 0ustar utkarsh2102utkarsh2102module InvisibleCaptcha class Railtie < Rails::Railtie initializer 'invisible_captcha.rails_integration' do ActiveSupport.on_load(:action_controller) do include InvisibleCaptcha::ControllerExt extend InvisibleCaptcha::ControllerExt::ClassMethods end ActiveSupport.on_load(:action_view) do include InvisibleCaptcha::ViewHelpers ActionView::Helpers::FormBuilder.send :include, InvisibleCaptcha::FormHelpers end end end end invisible-captcha-0.12.2/lib/invisible_captcha/controller_ext.rb0000644000175000017500000000630513541745065025542 0ustar utkarsh2102utkarsh2102module InvisibleCaptcha module ControllerExt module ClassMethods def invisible_captcha(options = {}) if respond_to?(:before_action) before_action(options) do detect_spam(options) end else before_filter(options) do detect_spam(options) end end end end private def detect_spam(options = {}) if timestamp_spam?(options) on_timestamp_spam(options) elsif honeypot_spam?(options) on_spam(options) end end def on_timestamp_spam(options = {}) if action = options[:on_timestamp_spam] send(action) else if respond_to?(:redirect_back) redirect_back(fallback_location: root_path, flash: { error: InvisibleCaptcha.timestamp_error_message }) else redirect_to :back, flash: { error: InvisibleCaptcha.timestamp_error_message } end end end def on_spam(options = {}) if action = options[:on_spam] send(action) else head(200) end end def timestamp_spam?(options = {}) enabled = if options.key?(:timestamp_enabled) options[:timestamp_enabled] else InvisibleCaptcha.timestamp_enabled end return false unless enabled @invisible_captcha_timestamp ||= session.delete(:invisible_captcha_timestamp) # Consider as spam if timestamp not in session, cause that means the form was not fetched at all unless @invisible_captcha_timestamp warn("Invisible Captcha timestamp not found in session.") return true end time_to_submit = Time.zone.now - DateTime.iso8601(@invisible_captcha_timestamp) threshold = options[:timestamp_threshold] || InvisibleCaptcha.timestamp_threshold # Consider as spam if form submitted too quickly if time_to_submit < threshold warn("Invisible Captcha timestamp threshold not reached (took #{time_to_submit.to_i}s).") return true end return false end def honeypot_spam?(options = {}) honeypot = options[:honeypot] scope = options[:scope] || controller_name.singularize if honeypot # If honeypot is defined for this controller-action, search for: # - honeypot: params[:subtitle] # - honeypot with scope: params[:topic][:subtitle] if params[honeypot].present? || (params[scope] && params[scope][honeypot].present?) warn("Invisible Captcha honeypot param '#{honeypot}' was present.") return true else # No honeypot spam detected, remove honeypot from params to avoid UnpermittedParameters exceptions params.delete(honeypot) if params.key?(honeypot) params[scope].try(:delete, honeypot) if params.key?(scope) end else InvisibleCaptcha.honeypots.each do |default_honeypot| if params[default_honeypot].present? warn("Invisible Captcha honeypot param '#{default_honeypot}' was present.") return true end end end false end def warn(message) logger.warn("Potential spam detected for IP #{request.remote_ip}. #{message}") end end end invisible-captcha-0.12.2/lib/invisible_captcha.rb0000644000175000017500000000431513541745065022476 0ustar utkarsh2102utkarsh2102require 'invisible_captcha/version' require 'invisible_captcha/controller_ext' require 'invisible_captcha/view_helpers' require 'invisible_captcha/form_helpers' require 'invisible_captcha/railtie' module InvisibleCaptcha class << self attr_writer :sentence_for_humans, :timestamp_error_message attr_accessor :honeypots, :timestamp_threshold, :timestamp_enabled, :visual_honeypots, :injectable_styles def init! # Default sentence for real users if text field was visible self.sentence_for_humans = -> { I18n.t('invisible_captcha.sentence_for_humans', default: 'If you are a human, ignore this field') } # Timestamp check enabled by default self.timestamp_enabled = true # Fastest time (in seconds) to expect a human to submit the form self.timestamp_threshold = 4 # Default error message for validator when form submitted too quickly self.timestamp_error_message = -> { I18n.t('invisible_captcha.timestamp_error_message', default: 'Sorry, that was too quick! Please resubmit.') } # Make honeypots visibles self.visual_honeypots = false # If enabled, you should call anywhere in of your layout the following helper, to inject the honeypot styles: # <%= invisible_captcha_styles %> self.injectable_styles = false end def sentence_for_humans call_lambda_or_return(@sentence_for_humans) end def timestamp_error_message call_lambda_or_return(@timestamp_error_message) end def setup yield(self) if block_given? end def honeypots @honeypots ||= (1..5).map { generate_random_honeypot } end def generate_random_honeypot "abcdefghijkl-mnopqrstuvwxyz".chars.sample(rand(10..20)).join end def get_honeypot honeypots.sample end def css_strategy [ "display:none;", "position:absolute!important;top:-9999px;left:-9999px;", "position:absolute!important;height:1px;width:1px;overflow:hidden;" ].sample end private def call_lambda_or_return(obj) obj.respond_to?(:call) ? obj.call : obj end end end InvisibleCaptcha.init! invisible-captcha-0.12.2/CHANGELOG.md0000644000175000017500000000675213541745065017554 0ustar utkarsh2102utkarsh2102# Changelog All notable changes to this project will be documented in this file. ## [0.12.2] - Allow new timestamp to be set during `on_timestamp_spam` callback (#53) ## [0.12.1] - Clear timestamp stored in `session[:invisible_captcha_timestamp]` (#50) - Rails 6 support ## [0.12.0] - Honeypot input with autocomplete="off" by default (#42) ## [0.11.0] - Improve logging (#40, #41) - Official Rails 5.2 support - Drop Ruby 2.1 from CI ## [0.10.0] - New timestamp on each request to avoid stale timestamps (#24) - Allow to inject styles manually anywhere in the layout (#27) - Allow to change threshold per action - Dynamic css strategy to hide the honeypot - Remove Ruby 1.9 support - Random default honeypots on each restart - Allow to pass html_options to honeypot input (#28) - Improvements on demo application and tests - Better strong parameters interaction (#30, #33) ## [0.9.3] - Rails 5.1 support (#29) - Modernize CI Rubies ## [0.9.2] - Rails 5.0 official support (#23) - Travis CI matrix improvements ## [0.9.1] - Add option (`timestamp_enabled`) to disable timestamp check (#22) ## [0.9.0] - Remove model style validations (#14) - Consider as spam if timestamp not in session (#11) - Allow to define a different threshold per action (#8) - Appraisals integration (#8) - CI improvements: use new Travis infrastructure (#8) ## [0.8.2] - Default timestamp action redirects to back (#19) - Stores timestamps as string in session (#17) ## [0.8.1] - Time-sensitive form submissions (#7) - I18n integration (#13) ## [0.8.0] - Better Rails integration with `ActiveSupport.on_load` callbacks (#5) - Allow to override settings via the view helper (#5) ## [0.7.0] - Revamped code base to allow more customizations (#2) - Added basic specs (#2) - Travis integration (#2) - Demo app (#2) ## [0.6.5] - Stop using Jeweler ## [0.6.4] - Docs! (#1) ## [0.6.3] - Internal re-naming ## [0.6.2] - Fix gem initialization ## [0.6.0] - Allow to configure via `InvisibleCaptcha.setup` block ## [0.5.0] - First version of controller filters [0.12.2]: https://github.com/markets/invisible_captcha/compare/v0.12.1...v0.12.2 [0.12.1]: https://github.com/markets/invisible_captcha/compare/v0.12.0...v0.12.1 [0.12.0]: https://github.com/markets/invisible_captcha/compare/v0.11.0...v0.12.0 [0.11.0]: https://github.com/markets/invisible_captcha/compare/v0.10.0...v0.11.0 [0.10.0]: https://github.com/markets/invisible_captcha/compare/v0.9.3...v0.10.0 [0.9.3]: https://github.com/markets/invisible_captcha/compare/v0.9.2...v0.9.3 [0.9.2]: https://github.com/markets/invisible_captcha/compare/v0.9.1...v0.9.2 [0.9.1]: https://github.com/markets/invisible_captcha/compare/v0.9.0...v0.9.1 [0.9.0]: https://github.com/markets/invisible_captcha/compare/v0.8.2...v0.9.0 [0.8.2]: https://github.com/markets/invisible_captcha/compare/v0.8.1...v0.8.2 [0.8.1]: https://github.com/markets/invisible_captcha/compare/v0.8.0...v0.8.1 [0.8.0]: https://github.com/markets/invisible_captcha/compare/v0.7.0...v0.8.0 [0.7.0]: https://github.com/markets/invisible_captcha/compare/v0.6.5...v0.7.0 [0.6.5]: https://github.com/markets/invisible_captcha/compare/v0.6.4...v0.6.5 [0.6.4]: https://github.com/markets/invisible_captcha/compare/v0.6.3...v0.6.4 [0.6.3]: https://github.com/markets/invisible_captcha/compare/v0.6.2...v0.6.3 [0.6.2]: https://github.com/markets/invisible_captcha/compare/v0.6.0...v0.6.2 [0.6.0]: https://github.com/markets/invisible_captcha/compare/v0.5.0...v0.6.0 [0.5.0]: https://github.com/markets/invisible_captcha/compare/v0.4.1...v0.5.0 invisible-captcha-0.12.2/invisible_captcha.gemspec0000644000175000017500000000202713541745065022746 0ustar utkarsh2102utkarsh2102require './lib/invisible_captcha/version' Gem::Specification.new do |spec| spec.name = "invisible_captcha" spec.version = InvisibleCaptcha::VERSION spec.authors = ["Marc Anguera Insa"] spec.email = ["srmarc.ai@gmail.com"] spec.description = "Unobtrusive, flexible and simple spam protection for Rails applications using honeypot strategy for better user experience." spec.summary = "Simple honeypot protection for RoR apps" spec.homepage = "https://github.com/markets/invisible_captcha" spec.license = "MIT" spec.files = `git ls-files`.split($/) spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] spec.add_dependency 'rails', '>= 3.2.0' spec.add_development_dependency 'rspec-rails', '~> 3.1' spec.add_development_dependency 'appraisal' spec.add_development_dependency 'test-unit', '~> 3.0' spec.add_development_dependency 'byebug' end invisible-captcha-0.12.2/Rakefile0000644000175000017500000000053213541745065017376 0ustar utkarsh2102utkarsh2102require "bundler/gem_tasks" require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) task :default => :spec desc 'Start development Rails app' task :web do app_path = 'spec/dummy' port = ENV['PORT'] || 3000 puts "Starting application in http://localhost:#{port} ... \n" Dir.chdir(app_path) exec("rails s -p #{port}") endinvisible-captcha-0.12.2/README.md0000644000175000017500000001717313541745065017221 0ustar utkarsh2102utkarsh2102# Invisible Captcha [![Gem](https://img.shields.io/gem/v/invisible_captcha.svg?style=flat-square)](https://rubygems.org/gems/invisible_captcha) [![Build Status](https://travis-ci.org/markets/invisible_captcha.svg)](https://travis-ci.org/markets/invisible_captcha) > Simple and flexible spam protection solution for Rails applications. Invisible Captcha provides different techniques to protect your application against spambots. The main protection is a solution based on the `honeypot` principle, which provides a better user experience, since there is no extra steps for real users, but for the bots. Essentially, the strategy consists on adding an input field :honey_pot: into the form that: - shouldn't be visible by the real users - should be left empty by the real users - will most be filled by spam bots It also comes with a time-sensitive :hourglass: form submission. ## Installation Invisible Captcha is tested against Rails `>= 3.2` and Ruby `>= 2.2`. Add this line to your Gemfile and then execute `bundle install`: ```ruby gem 'invisible_captcha' ``` ## Usage View code: ```erb <%= form_for(@topic) do |f| %> <%= f.invisible_captcha :subtitle %> <%= invisible_captcha :subtitle, :topic %> <% end %> ``` Controller code: ```ruby class TopicsController < ApplicationController invisible_captcha only: [:create, :update], honeypot: :subtitle end ``` This method will act as a `before_action` that triggers when spam is detected (honeypot field has some value). By default it responds with no content (only headers: `head(200)`). This is a good default, since the bot will surely read the response code and will think that it has achieved to submit the form properly. But, anyway, you are able to define your own callback by passing a method to the `on_spam` option: ```ruby class TopicsController < ApplicationController invisible_captcha only: [:create, :update], on_spam: :your_spam_callback_method private def your_spam_callback_method redirect_to root_path end end ``` Note that is not mandatory to specify a `honeypot` attribute (nor in the view, nor in the controller). In this case, the engine will take a random field from `InvisibleCaptcha.honeypots`. So, if you're integrating it following this path, in your form: ```erb <%= form_tag(new_contact_path) do |f| %> <%= invisible_captcha %> <% end %> ``` In you controller: ``` invisible_captcha only: [:new_contact] ``` ## Options and customization This section contains a description of all plugin options and customizations. ### Plugin options: You can customize: - `sentence_for_humans`: text for real users if input field was visible. By default, it uses I18n (see below). - `honeypots`: collection of default honeypots. Used by the view helper, called with no args, to generate a random honeypot field name. By default, a random collection is already generated. - `visual_honeypots`: make honeypots visible, also useful to test/debug your implementation. - `timestamp_threshold`: fastest time (in seconds) to expect a human to submit the form (see [original article by Yoav Aner](https://blog.gingerlime.com/2012/simple-detection-of-comment-spam-in-rails/) outlining the idea). By default, 4 seconds. **NOTE:** It's recommended to deactivate the autocomplete feature to avoid false positives (`autocomplete="off"`). - `timestamp_enabled`: option to disable the time threshold check at application level. Could be useful, for example, on some testing scenarios. By default, true. - `timestamp_error_message`: flash error message thrown when form submitted quicker than the `timestamp_threshold` value. It uses I18n by default. - `injectable_styles`: if enabled, you should call anywhere in your layout the following helper `<%= invisible_captcha_styles %>`. This allows you to inject styles, for example, in ``. False by default, styles are injected inline with the honeypot. To change these defaults, add the following to an initializer (recommended `config/initializers/invisible_captcha.rb`): ```ruby InvisibleCaptcha.setup do |config| # config.honeypots << ['more', 'fake', 'attribute', 'names'] # config.visual_honeypots = false # config.timestamp_threshold = 4 # config.timestamp_enabled = true # config.injectable_styles = false # Leave these unset if you want to use I18n (see below) # config.sentence_for_humans = 'If you are a human, ignore this field' # config.timestamp_error_message = 'Sorry, that was too quick! Please resubmit.' end ``` ### Controller method options: The `invisible_captcha` method accepts some options: - `only`: apply to given controller actions. - `except`: exclude to given controller actions. - `honeypot`: name of custom honeypot. - `scope`: name of scope, ie: 'topic[subtitle]' -> 'topic' is the scope. - `on_spam`: custom callback to be called on spam detection. - `timestamp_enabled`: enable/disable this technique at action level. - `on_timestamp_spam`: custom callback to be called when form submitted too quickly. The default action redirects to `:back` printing a warning in `flash[:error]`. - `timestamp_threshold`: custom threshold per controller/action. Overrides the global value for `InvisibleCaptcha.timestamp_threshold`. ### View helpers options: Using the view/form helper you can override some defaults for the given instance. Actually, it allows to change: - `sentence_for_humans` ```erb <%= form_for(@topic) do |f| %> <%= f.invisible_captcha :subtitle, sentence_for_humans: "hey! leave this input empty!" %> <% end %> ``` - `visual_honeypots` ```erb <%= form_for(@topic) do |f| %> <%= f.invisible_captcha :subtitle, visual_honeypots: true %> <% end %> ``` You can also pass html options to the input: ```erb <%= invisible_captcha :subtitle, :topic, id: "your_id", class: "your_class" %> ``` ### I18n `invisible_captcha` tries to use I18n when it's available by default. The keys it looks for are the following: ```yaml en: invisible_captcha: sentence_for_humans: "If you are human, ignore this field" timestamp_error_message: "Sorry, that was too quick! Please resubmit." ``` You can override the english ones in your own i18n config files as well as add new ones for other locales. If you intend to use I18n with `invisible_captcha`, you _must not_ set `sentence_for_humans` or `timestamp_error_message` to strings in the setup phase. ## Testing your controllers If you're encountering unexpected behaviour while testing controllers that use the `invisible_captcha` action filter, you may want to disable timestamp check for the test environment: ```ruby # test/test_helper.rb, spec/rails_helper.rb, ... InvisibleCaptcha.timestamp_enabled = false ``` Another option is to wait for the timestamp check to be valid: ```ruby # Maybe in a before block InvisibleCaptcha.init! InvisibleCaptcha.timestamp_threshold = 1 # Before testing your controller action sleep InvisibleCaptcha.timestamp_threshold ``` ## Contribute Any kind of idea, feedback or bug report are welcome! Open an [issue](https://github.com/markets/invisible_captcha/issues) or send a [pull request](https://github.com/markets/invisible_captcha/pulls). ## Development Clone/fork this repository, start to hack on it and send a pull request. Run the test suite: ``` $ bundle exec rspec ``` Run the test suite against all supported versions: ``` $ bundle exec appraisal install $ bundle exec appraisal rspec ``` Run specs against specific version: ``` $ bundle exec appraisal rails-5.2 rspec ``` ### Demo Start a sample Rails app ([source code](spec/dummy)) with `InvisibleCaptcha` integrated: ``` $ bundle exec rake web # PORT=4000 (default: 3000) ``` ## License Copyright (c) Marc Anguera. Invisible Captcha is released under the [MIT](LICENSE) License. invisible-captcha-0.12.2/.travis.yml0000644000175000017500000000200513541745065020037 0ustar utkarsh2102utkarsh2102language: ruby cache: bundler sudo: false rvm: - ruby-head - 2.6.2 - 2.5.5 - 2.4.5 - 2.3.8 - 2.2.10 gemfile: - gemfiles/rails_6.0.gemfile - gemfiles/rails_5.2.gemfile - gemfiles/rails_5.1.gemfile - gemfiles/rails_5.0.gemfile - gemfiles/rails_4.2.gemfile - gemfiles/rails_3.2.gemfile before_install: # Rails 4.x requires Bundler version < 2.0. - "find /home/travis/.rvm/rubies -wholename '*default/bundler-*.gemspec' -delete" - rvm @global do gem uninstall bundler -a -x - rvm @global do yes | gem install bundler -v '< 2' matrix: exclude: - rvm: 2.4.5 gemfile: gemfiles/rails_6.0.gemfile - rvm: 2.3.8 gemfile: gemfiles/rails_6.0.gemfile - rvm: 2.2.10 gemfile: gemfiles/rails_6.0.gemfile - rvm: ruby-head gemfile: gemfiles/rails_3.2.gemfile - rvm: 2.6.2 gemfile: gemfiles/rails_3.2.gemfile - rvm: 2.5.5 gemfile: gemfiles/rails_3.2.gemfile - rvm: 2.4.5 gemfile: gemfiles/rails_3.2.gemfile allow_failures: - rvm: ruby-headinvisible-captcha-0.12.2/.gitignore0000644000175000017500000000017713541745065017726 0ustar utkarsh2102utkarsh2102.bundle pkg .rvmrc .ruby-version .ruby-gemset Gemfile.lock *.gemfile.lock spec/dummy/log/*.log spec/dummy/tmp/ .byebug_history invisible-captcha-0.12.2/Gemfile0000644000175000017500000000004713541745065017225 0ustar utkarsh2102utkarsh2102source 'https://rubygems.org' gemspec