simple_captcha2-0.4.3/ 0000755 0000041 0000041 00000000000 13124500445 014602 5 ustar www-data www-data simple_captcha2-0.4.3/Rakefile 0000644 0000041 0000041 00000002500 13124500445 016244 0 ustar www-data www-data begin require 'bundler/setup' rescue LoadError puts 'You must `gem install bundler` and `bundle install` to run rake tasks' end require 'rdoc/task' RDoc::Task.new(:rdoc) do |rdoc| rdoc.rdoc_dir = 'rdoc' rdoc.title = 'SimpleCaptcha' rdoc.options << '--line-numbers' rdoc.rdoc_files.include('README.rdoc') rdoc.rdoc_files.include('lib/**/*.rb') end APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__) if File.exist? APP_RAKEFILE load 'rails/tasks/engine.rake' end namespace :dummy do desc 'Setup dummy Rails app for test purpose' task :setup do require 'rails' require 'simple_captcha' require File.expand_path('../test/lib/generators/simple_captcha/dummy/dummy_generator', __FILE__) SimpleCaptcha::DummyGenerator.start %w(--quiet) end desc 'destroy dummy Rails app under test/dummy' task :destroy do FileUtils.rm_rf "test/dummy" if File.exist?("test/dummy") end desc 'redo' task :redo do sh 'rake dummy:destroy' sh 'rake dummy:setup' sh 'rake app:db:migrate' sh 'rake app:db:migrate RAILS_ENV=test' end end Bundler::GemHelper.install_tasks :name => 'simple_captcha2' require 'rake/testtask' Rake::TestTask.new(:test) do |t| t.libs << 'lib' t.libs << 'test' t.pattern = 'test/**/*_test.rb' t.verbose = false end task default: :test simple_captcha2-0.4.3/lib/ 0000755 0000041 0000041 00000000000 13124500445 015350 5 ustar www-data www-data simple_captcha2-0.4.3/lib/simple_captcha/ 0000755 0000041 0000041 00000000000 13124500445 020324 5 ustar www-data www-data simple_captcha2-0.4.3/lib/simple_captcha/simple_captcha_data_mongoid.rb 0000644 0000041 0000041 00000001065 13124500445 026334 0 ustar www-data www-data module SimpleCaptcha class SimpleCaptchaData include Mongoid::Document include Mongoid::Timestamps field :key, type: String field :value, type: String class << self def get_data(key) data = where(:key => key).first || new(:key => key) end def remove_data(key) where(:key => key).delete_all clear_old_data(1.hour.ago) end def clear_old_data(time = 1.hour.ago) return unless Time === time where(:updated_at.lte => time).delete_all end end end end simple_captcha2-0.4.3/lib/simple_captcha/utils.rb 0000644 0000041 0000041 00000001754 13124500445 022020 0 ustar www-data www-data require 'digest/sha1' module SimpleCaptcha #:nodoc module Utils #:nodoc # Execute command with params and return output if exit status equal expected_outcodes def self.run(cmd, params = "", expected_outcodes = 0) command = %Q[#{cmd} #{params}].gsub(/\s+/, " ") command = "#{command} 2>&1" unless (image_magick_path = SimpleCaptcha.image_magick_path).blank? command = File.join(image_magick_path, command) end output = `#{command}` unless [expected_outcodes].flatten.include?($?.exitstatus) raise ::StandardError, "Error while running #{cmd}: #{output}" end output end def self.simple_captcha_value(key) #:nodoc SimpleCaptchaData.get_data(key).value rescue nil end def self.simple_captcha_passed!(key) #:nodoc SimpleCaptchaData.remove_data(key) end def self.generate_key(*args) args << (Time.now.to_f * 1_000_000_000).to_s Digest::SHA1.hexdigest(args.join) end end end simple_captcha2-0.4.3/lib/simple_captcha/form_builder.rb 0000644 0000041 0000041 00000002602 13124500445 023322 0 ustar www-data www-data module SimpleCaptcha module FormBuilder def self.included(base) base.send(:include, SimpleCaptcha::ViewHelper) base.send(:include, SimpleCaptcha::FormBuilder::ClassMethods) base.send(:include, ActionView::Helpers) if defined? Sprockets::Helpers base.send(:include, Sprockets::Helpers::RailsHelper) base.send(:include, Sprockets::Helpers::IsolatedHelper) end base.delegate :render, :session, :to => :template end module ClassMethods # Example: # <% form_for :post, :url => posts_path do |form| %> # ... # <%= form.simple_captcha :label => "Enter numbers.." %> # <% end %> # def simple_captcha(options = {}) options.update :object => @object_name show_simple_captcha(objectify_options(options)) end private def template @template end def simple_captcha_field(options={}) html = {:autocomplete => 'off', :autocorrect => 'off', :autocapitalize => 'off', :required => 'required', :value => ''} html.merge!(options[:input_html] || {}) html[:placeholder] = options[:placeholder] || I18n.t('simple_captcha.placeholder') text_field(:captcha, html) + hidden_field(:captcha_key, {:value => options[:field_value], :id => simple_captch_hidden_field_id(options)}) end end end end simple_captcha2-0.4.3/lib/simple_captcha/engine.rb 0000644 0000041 0000041 00000001144 13124500445 022116 0 ustar www-data www-data # encoding: utf-8 require 'rails' module SimpleCaptcha class Engine < ::Rails::Engine config.before_initialize do ActiveSupport.on_load :active_record do ActiveRecord::Base.send(:include, SimpleCaptcha::ModelHelpers) end end config.after_initialize do ActionView::Base.send(:include, SimpleCaptcha::ViewHelper) ActionView::Helpers::FormBuilder.send(:include, SimpleCaptcha::FormBuilder) if Object.const_defined?("Formtastic") require 'simple_captcha/formtastic' end end config.app_middleware.use SimpleCaptcha::Middleware end end simple_captcha2-0.4.3/lib/simple_captcha/controller.rb 0000644 0000041 0000041 00000002204 13124500445 023032 0 ustar www-data www-data module SimpleCaptcha #:nodoc module ControllerHelpers #:nodoc # This method is to validate the simple captcha in controller. # It means when the captcha is controller based i.e. :object has not been passed to the method show_simple_captcha. # # *Example* # # If you want to save an object say @user only if the captcha is validated then do like this in action... # # if simple_captcha_valid? # @user.save # else # flash[:notice] = "captcha did not match" # redirect_to :action => "myaction" # end def simple_captcha_valid? return true if SimpleCaptcha.always_pass return @_simple_captcha_result unless !defined?(@_simple_captcha_result) || @_simple_captcha_result.nil? if params[:captcha] captcha_key = params[:captcha_key] || session[:captcha] data = SimpleCaptcha::Utils::simple_captcha_value(captcha_key) result = data == params[:captcha].delete(" ").upcase SimpleCaptcha::Utils::simple_captcha_passed!(captcha_key) if result @_simple_captcha_result = result result else false end end end end simple_captcha2-0.4.3/lib/simple_captcha/formtastic.rb 0000644 0000041 0000041 00000000572 13124500445 023030 0 ustar www-data www-data if defined? Formtastic require 'formtastic/version' if Formtastic::VERSION < '2.2' raise 'Only Formtastic Version 2.2 or greater is supported by SimpleCaptcha' end class SimpleCaptchaInput include Formtastic::Inputs::Base def to_html options.update :object => sanitized_object_name builder.send(:show_simple_captcha, options) end end end simple_captcha2-0.4.3/lib/simple_captcha/version.rb 0000644 0000041 0000041 00000000064 13124500445 022336 0 ustar www-data www-data module SimpleCaptcha VERSION = "0.4.3".freeze end simple_captcha2-0.4.3/lib/simple_captcha/middleware.rb 0000644 0000041 0000041 00000007663 13124500445 023002 0 ustar www-data www-data # encoding: utf-8 module SimpleCaptcha class Middleware include SimpleCaptcha::ImageHelpers include SimpleCaptcha::ViewHelper DEFAULT_SEND_FILE_OPTIONS = { :type => 'application/octet-stream'.freeze, :disposition => 'attachment'.freeze, }.freeze REFRESH_FORMATS = { :jquery => %Q{ $("#%{id}").attr('src', '%{url}'); $("#%{captcha_hidden_field_id}").attr('value', '%{key}'); }.freeze, :plain_javascript => %Q{ var img = document.getElementById("%{id}"); if (img != null) { img.src = "%{url}"; } var hidden = document.getElementById("%{captcha_hidden_field_id}"); if (hidden != null) { hidden.value = "%{key}"; } }.freeze, :prototype => %Q{ $("%{id}").setAttribute('src', '%{url}'); $("%{captcha_hidden_field_id}").setAttribute('value', '%{key}'); }.freeze, }.freeze def initialize(app, options={}) @app = app self end def call(env) # :nodoc: if env["REQUEST_METHOD"] == "GET" && captcha_path?(env['PATH_INFO']) request = Rack::Request.new(env) if request.params.present? && request.params['code'].present? make_image(env) else refresh_code(env) end else @app.call(env) end end protected def make_image(env, headers = {}, status = 404) request = Rack::Request.new(env) code = request.params["code"] body = [] if Utils::simple_captcha_value(code) #status, headers, body = @app.call(env) #status = 200 #body = generate_simple_captcha_image(code) #headers['Content-Type'] = 'image/jpeg' send_data(generate_simple_captcha_image(code), :type => 'image/jpeg', :disposition => 'inline', :filename => 'simple_captcha.jpg') else [status, headers, body] end end def captcha_path?(request_path) request_path.include?('/simple_captcha') end def send_file(path, options = {}) raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path) options[:filename] ||= File.basename(path) unless options[:url_based_filename] status = options[:status] || 200 headers = {"Content-Disposition" => "#{options[:disposition]}; filename='#{options[:filename]}'", "Content-Type" => options[:type], 'Content-Transfer-Encoding' => 'binary', 'Cache-Control' => 'private'} response_body = File.open(path, "rb") [status, headers, response_body] end def send_data(response_body, options = {}) status = options[:status] || 200 headers = {"Content-Disposition" => "#{options[:disposition]}; filename='#{options[:filename]}'", "Content-Type" => options[:type], 'Content-Transfer-Encoding' => 'binary', 'Cache-Control' => 'private'} [status, headers, [response_body]] end def refresh_code(env) request = Rack::Request.new(env) request.session.delete :captcha key = simple_captcha_key(nil, request) options = {} options[:field_value] = set_simple_captcha_data(key, options) url = simple_captcha_image_url(key, options) status = 200 id = request.params['id'] captcha_hidden_field_id = simple_captch_hidden_field_id(id) format = SimpleCaptcha.refresh_format.to_sym raise ::ArgumentError, "Format adapter '#{format}' is not available" unless format.in?(REFRESH_FORMATS) body = REFRESH_FORMATS[format] % {id: id, url: url, captcha_hidden_field_id: captcha_hidden_field_id, key: key} headers = {'Content-Type' => 'text/javascript; charset=utf-8', "Content-Disposition" => "inline; filename='captcha.js'", "Content-Length" => body.length.to_s}.merge(SimpleCaptcha.extra_response_headers) [status, headers, [body]] end end end simple_captcha2-0.4.3/lib/simple_captcha/view.rb 0000644 0000041 0000041 00000013224 13124500445 021625 0 ustar www-data www-data module SimpleCaptcha #:nodoc module ViewHelper #:nodoc # Simple Captcha is a very simplified captcha. # # It can be used as a *Model* or a *Controller* based Captcha depending on what options # we are passing to the method show_simple_captcha. # # *show_simple_captcha* method will return the image, the label and the text box. # This method should be called from the view within your form as... # # <%= show_simple_captcha %> # # The available options to pass to this method are # * label # * object # # Label: # # default label is "type the text from the image", it can be modified by passing :label as # # <%= show_simple_captcha(:label => "new captcha label") %>. # # *Object* # # This option is needed to create a model based captcha. # If this option is not provided, the captcha will be controller based and # should be checked in controller's action just by calling the method simple_captcha_valid? # # To make a model based captcha give this option as... # # <%= show_simple_captcha(:object => "user") %> # and also call the method apply_simple_captcha in the model # this will consider "user" as the object of the model class. # # *Examples* # * controller based # <%= show_simple_captcha(:label => "Human Authentication: type the text from image above") %> # * model based # <%= show_simple_captcha(:object => "person", :label => "Human Authentication: type the text from image above") %> # # Find more detailed examples with sample images here on my blog http://EXPRESSICA.com # # All Feedbacks/CommentS/Issues/Queries are welcome. def show_simple_captcha(options = {}) render :partial => SimpleCaptcha.partial_path, :locals => { :simple_captcha_options => simple_captcha_options(options) } end def simple_captcha_options(options = {}) key = simple_captcha_key(options[:object]) if options[:multiple] === false # It's not the first captcha, we only need to return the key options[:field_value] = key else # It's the first captcha in the page, we generate a new key options[:field_value] = set_simple_captcha_data(key, options) end { :image => simple_captcha_image(key, options), :label => I18n.t('simple_captcha.label'), :field => simple_captcha_field(options), :refresh_button => simple_captcha_refresh_button(options), }.merge(options) end private def simple_captcha_image(simple_captcha_key, options = {}) url = simple_captcha_image_url simple_captcha_key, options: options id = simple_captcha_image_id(options) tag('img', :src => url, :alt => 'captcha', :id => id) end def simple_captcha_image_url(simple_captcha_key, options = {}) defaults = {} defaults[:time] = options[:time] || Time.now.to_i query = defaults.to_query path = "/simple_captcha?code=#{simple_captcha_key}{query}" build_url(options, path) end def build_url(options, path) if defined?(request) && request "#{request.protocol}#{request.host_with_port}#{ENV['RAILS_RELATIVE_URL_ROOT']}#{path}" else "#{ENV['RAILS_RELATIVE_URL_ROOT']}#{path}" end end def simple_captcha_field(options={}) html = {:autocomplete => 'off', :autocorrect => 'off', :autocapitalize => 'off', :required => 'required'} html.merge!(options[:input_html] || {}) html[:placeholder] = options[:placeholder] || I18n.t('simple_captcha.placeholder') if options[:object] text_field(options[:object], :captcha, html.merge(:value => '')) + hidden_field(options[:object], :captcha_key, {:value => options[:field_value], :id => simple_captch_hidden_field_id(options)}) else text_field_tag(:captcha, nil, html) + hidden_field_tag(:captcha_key, options[:field_value], :id => simple_captch_hidden_field_id(options)) end end def simple_captcha_refresh_button(options={}) html = {remote: true} html.merge!(options[:refresh_button_html] || {}) text = options[:refresh_button_text] || I18n.t('simple_captcha.refresh_button_text', default: 'Refresh') url = build_url(options, "/simple_captcha?id=#{simple_captcha_image_id(options)}") link_to(text, url, html) end def simple_captcha_image_id(options={}) "simple_captcha-#{options[:field_value][0..10]}" end def simple_captch_hidden_field_id(image_id) image_id = simple_captcha_image_id(image_id) if image_id.is_a?(Hash) "simple-captcha-hidden-field-#{ image_id }" end def set_simple_captcha_data(key, options={}) code_type = options[:code_type] value = generate_simple_captcha_data(code_type) data = SimpleCaptcha::SimpleCaptchaData.get_data(key) data.value = value data.save key end def generate_simple_captcha_data(code) value = '' case code when 'numeric' then SimpleCaptcha.length.times{value << (48 + rand(10)).chr} else SimpleCaptcha.length.times{value << (65 + rand(26)).chr} end return value end def simple_captcha_key(key_name = nil, prequest = request) local_session = prequest.try(:session) || session if key_name.nil? local_session[:captcha] ||= SimpleCaptcha::Utils.generate_key(local_session[:id].to_s, 'captcha') else SimpleCaptcha::Utils.generate_key(local_session[:id].to_s, key_name) end end end end simple_captcha2-0.4.3/lib/simple_captcha/model_helpers.rb 0000644 0000041 0000041 00000004562 13124500445 023502 0 ustar www-data www-data module SimpleCaptcha #:nodoc module ModelHelpers #:nodoc def self.included(base) base.extend(SingletonMethods) end # To implement model based simple captcha use this method in the model as... # # class User < ActiveRecord::Base # # apply_simple_captcha :message => "my customized message" # # end # # Customize the error message by using :message, the default message is "Captcha did not match". # As in the applications captcha is needed with a very few cases like signing up the new user, but # not every time you need to authenticate the captcha with @user.save. So as to maintain simplicity # here we have the explicit method to save the instace with captcha validation as... # # * to validate the instance # # @user.valid_with_captcha? # whene captcha validation is required. # # @user.valid? # when captcha validation is not required. # # * to save the instance # # @user.save_with_captcha # whene captcha validation is required. # # @user.save # when captcha validation is not required. module SingletonMethods def apply_simple_captcha(options = {}) options = { :add_to_base => false }.merge(options) class_attribute :simple_captcha_options self.simple_captcha_options = options unless self.is_a?(ClassMethods) include InstanceMethods extend ClassMethods attr_accessor :captcha, :captcha_key end end end module ClassMethods end module InstanceMethods def valid_with_captcha? [valid?, is_captcha_valid?].all? end def is_captcha_valid? return true if SimpleCaptcha.always_pass if captcha && captcha.upcase.delete(" ") == SimpleCaptcha::Utils::simple_captcha_value(captcha_key) SimpleCaptcha::Utils::simple_captcha_passed!(captcha_key) return true else message = simple_captcha_options[:message] || I18n.t(self.class.model_name.to_s.downcase, :scope => [:simple_captcha, :message], :default => :default) simple_captcha_options[:add_to_base] ? errors.add(:base, message) : errors.add(:captcha, message) return false end end def save_with_captcha valid_with_captcha? && save(:validate => false) end end end end simple_captcha2-0.4.3/lib/simple_captcha/simple_captcha_data.rb 0000644 0000041 0000041 00000001640 13124500445 024617 0 ustar www-data www-data module SimpleCaptcha class SimpleCaptchaData < ::ActiveRecord::Base if ::ActiveRecord::VERSION::MAJOR >= 3 # Fixes deprecation warning in Rails 3.2: # DEPRECATION WARNING: Calling set_table_name is deprecated. Please use `self.table_name = 'the_name'` instead. self.table_name = "simple_captcha_data" else set_table_name "simple_captcha_data" end if ::ActiveRecord::VERSION::MAJOR == 3 and defined? attr_protected attr_protected end class << self def get_data(key) where(key: key).first_or_initialize end def remove_data(key) where(["#{connection.quote_column_name(:key)} = ?", key]).delete_all clear_old_data(1.hour.ago) end def clear_old_data(time = 1.hour.ago) return unless Time === time where(["#{connection.quote_column_name(:updated_at)} < ?", time]).delete_all end end end end simple_captcha2-0.4.3/lib/simple_captcha/image.rb 0000644 0000041 0000041 00000005730 13124500445 021740 0 ustar www-data www-data require 'tempfile' module SimpleCaptcha #:nodoc module ImageHelpers #:nodoc mattr_accessor :image_styles @@image_styles = { 'embosed_silver' => ['-fill darkblue', '-shade 20x60', '-background white'], 'simply_red' => ['-fill darkred', '-background white'], 'simply_green' => ['-fill darkgreen', '-background white'], 'simply_blue' => ['-fill darkblue', '-background white'], 'distorted_black' => ['-fill darkblue', '-edge 10', '-background white'], 'all_black' => ['-fill darkblue', '-edge 2', '-background white'], 'charcoal_grey' => ['-fill darkblue', '-charcoal 5', '-background white'], 'almost_invisible' => ['-fill red', '-solarize 50', '-background white'] } DISTORTIONS = ['low', 'medium', 'high'] IMPLODES = { 'none' => 0, 'low' => 0.1, 'medium' => 0.2, 'high' => 0.3 } DEFAULT_IMPLODE = 'medium' class << self def image_params(key = 'simply_blue') image_keys = @@image_styles.keys style = begin if key == 'random' image_keys[rand(image_keys.length)] else image_keys.include?(key) ? key : 'simply_blue' end end @@image_styles[style] end def distortion(key='low') key = key == 'random' ? DISTORTIONS[rand(DISTORTIONS.length)] : DISTORTIONS.include?(key) ? key : 'low' case key.to_s when 'low' then return [0 + rand(2), 80 + rand(20)] when 'medium' then return [2 + rand(2), 50 + rand(20)] when 'high' then return [4 + rand(2), 30 + rand(20)] end end def implode IMPLODES[SimpleCaptcha.implode] || IMPLODES[DEFAULT_IMPLODE] end end if RUBY_VERSION < '1.9' class Tempfile < ::Tempfile # Replaces Tempfile's +make_tmpname+ with one that honors file extensions. def make_tmpname(basename, n = 0) extension = File.extname(basename) sprintf("%s,%d,%d%s", File.basename(basename, extension), $$, n, extension) end end end private def generate_simple_captcha_image(simple_captcha_key) #:nodoc amplitude, frequency = ImageHelpers.distortion(SimpleCaptcha.distortion) text = Utils::simple_captcha_value(simple_captcha_key) params = ImageHelpers.image_params(SimpleCaptcha.image_style).dup params << "-size #{SimpleCaptcha.image_size}" params << "-wave #{amplitude}x#{frequency}" params << "-gravity Center" params << "-pointsize 22" params << "-implode #{ImageHelpers.implode}" params << "label:#{text}" unless SimpleCaptcha.font.empty? params << "-font #{SimpleCaptcha.font}" end if SimpleCaptcha.noise and SimpleCaptcha.noise > 0 params << "-evaluate Uniform-noise #{SimpleCaptcha.noise}" end params << "jpeg:-" SimpleCaptcha::Utils::run("convert", params.join(' ')) end end end simple_captcha2-0.4.3/lib/generators/ 0000755 0000041 0000041 00000000000 13124500445 017521 5 ustar www-data www-data simple_captcha2-0.4.3/lib/generators/templates/ 0000755 0000041 0000041 00000000000 13124500445 021517 5 ustar www-data www-data simple_captcha2-0.4.3/lib/generators/templates/partial.erb 0000644 0000041 0000041 00000002113 13124500445 023642 0 ustar www-data www-data