Commit 62bac6f22031a0166608bdd83cc0e1f98d553649

Authored by Antonio Terceiro
1 parent 7410bc19

Adding plugin

(ActionItem1732)
vendor/plugins/rails-math-captcha/MIT-LICENSE 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +Copyright (c) 2007 [name of plugin creator]
  2 +
  3 +Permission is hereby granted, free of charge, to any person obtaining
  4 +a copy of this software and associated documentation files (the
  5 +"Software"), to deal in the Software without restriction, including
  6 +without limitation the rights to use, copy, modify, merge, publish,
  7 +distribute, sublicense, and/or sell copies of the Software, and to
  8 +permit persons to whom the Software is furnished to do so, subject to
  9 +the following conditions:
  10 +
  11 +The above copyright notice and this permission notice shall be
  12 +included in all copies or substantial portions of the Software.
  13 +
  14 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
... ...
vendor/plugins/rails-math-captcha/README 0 → 100644
... ... @@ -0,0 +1,45 @@
  1 +MathCaptcha
  2 +===========
  3 +
  4 +TODO: Create form helpers
  5 +
  6 +Validates your Model to be saved by a human (or very clever script) by asking
  7 +the user to solve a very basic mathematical equation.
  8 +
  9 +It does not use the session to store the secret, but uses AES from EzCrypto.
  10 +
  11 +
  12 +Requirements
  13 +============
  14 + * gem ezcrypto
  15 + * users who can calculate
  16 +
  17 +Usage
  18 +=====
  19 +
  20 +In your Model < ActiveRecord::Base
  21 +
  22 + has_captcha
  23 +
  24 +
  25 +In your form view:
  26 +
  27 + <%= @model.captcha.task %> = ?
  28 + <%= form.text_field :captcha_solution %>
  29 + <%= form.hidden_field :captcha_secret %>
  30 +
  31 +
  32 +If you want to skip the validation (in tests/specs), you can
  33 +
  34 + Model.skip_captcha! # or
  35 + @model.skip_captcha!
  36 +
  37 +and turn that off by
  38 +
  39 + Model.dont_skip_captcha! # or
  40 + @model.dont_skip_captcha!
  41 +
  42 +
  43 +
  44 +Copyright (c) 2007 Pat Nakajima, released under the MIT license
  45 +Copyright (c) 2009 Niklas Hofer, released under the MIT license
... ...
vendor/plugins/rails-math-captcha/Rakefile 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +require 'rake'
  2 +require 'rake/testtask'
  3 +require 'rake/rdoctask'
  4 +
  5 +desc 'Default: run unit tests.'
  6 +task :default => :test
  7 +
  8 +desc 'Test the math_captcha plugin.'
  9 +Rake::TestTask.new(:test) do |t|
  10 + t.libs << 'lib'
  11 + t.pattern = 'test/**/*_test.rb'
  12 + t.verbose = true
  13 +end
  14 +
  15 +desc 'Generate documentation for the math_captcha plugin.'
  16 +Rake::RDocTask.new(:rdoc) do |rdoc|
  17 + rdoc.rdoc_dir = 'rdoc'
  18 + rdoc.title = 'MathCaptcha'
  19 + rdoc.options << '--line-numbers' << '--inline-source'
  20 + rdoc.rdoc_files.include('README')
  21 + rdoc.rdoc_files.include('lib/**/*.rb')
  22 +end
... ...
vendor/plugins/rails-math-captcha/init.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +require 'math_captcha'
0 2 \ No newline at end of file
... ...
vendor/plugins/rails-math-captcha/install.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +# Install hook code here
... ...
vendor/plugins/rails-math-captcha/lib/math_captcha.rb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +require 'math_captcha/captcha'
  2 +require 'math_captcha/has_captcha'
... ...
vendor/plugins/rails-math-captcha/lib/math_captcha/captcha.rb 0 → 100644
... ... @@ -0,0 +1,68 @@
  1 +require 'rubygems'
  2 +require 'ezcrypto'
  3 +class Captcha
  4 + NUMBERS = (1..9).to_a
  5 + OPERATORS = [:+, :-, :*]
  6 +
  7 + attr_reader :x, :y, :operator
  8 +
  9 + def initialize(x=nil, y=nil, operator=nil)
  10 + @x = x || NUMBERS.sort_by{rand}.first
  11 + @y = y || NUMBERS.sort_by{rand}.first
  12 + @operator = operator || OPERATORS.sort_by{rand}.first
  13 + end
  14 +
  15 + # Only the #to_secret is shared with the client.
  16 + # It can be reused here to create the Captcha again
  17 + def self.from_secret(secret)
  18 + yml = cipher.decrypt64 secret
  19 + args = YAML.load(yml)
  20 + new(args[:x], args[:y], args[:operator])
  21 + end
  22 +
  23 + def self.cipher
  24 + EzCrypto::Key.with_password key, 'bad_fixed_salt'
  25 + end
  26 +
  27 + def self.key
  28 + 'ultrasecret'
  29 + end
  30 +
  31 +
  32 + def check(answer)
  33 + answer == solution
  34 + end
  35 +
  36 + def task
  37 + "#{@x} #{@operator.to_s} #{@y}"
  38 + end
  39 + def task_with_questionmark
  40 + "#{@x} #{@operator.to_s} #{@y} = ?"
  41 + end
  42 + alias_method :to_s, :task
  43 +
  44 + def solution
  45 + @x.send @operator, @y
  46 + end
  47 +
  48 + def to_secret
  49 + cipher.encrypt64(to_yaml)
  50 + end
  51 +
  52 + def to_yaml
  53 + YAML::dump({
  54 + :x => x,
  55 + :y => y,
  56 + :operator => operator
  57 + })
  58 + end
  59 +
  60 + private
  61 + def cipher
  62 + @cipher ||= self.class.cipher
  63 + end
  64 + def reset_cipher
  65 + @cipher = nil
  66 + end
  67 +
  68 +end
... ...
vendor/plugins/rails-math-captcha/lib/math_captcha/has_captcha.rb 0 → 100644
... ... @@ -0,0 +1,54 @@
  1 +module MathCaptcha
  2 + module HasCaptcha
  3 + module InstanceMethods
  4 + def must_solve_captcha
  5 + self.errors.add(:captcha_solution, "wrong answer.") unless self.captcha.check(self.captcha_solution.to_i)
  6 + end
  7 + def skip_captcha!
  8 + self.class.skip_captcha!
  9 + end
  10 + def skip_captcha?
  11 + self.class.skip_captcha?
  12 + end
  13 + def captcha
  14 + @captcha ||= Captcha.new
  15 + end
  16 + def captcha_secret=(secret)
  17 + @captcha = Captcha.from_secret(secret)
  18 + end
  19 + def captcha_secret
  20 + captcha.to_secret
  21 + end
  22 + end
  23 +
  24 + module ClassMethods
  25 + def has_captcha
  26 + include InstanceMethods
  27 + attr_accessor :captcha_solution
  28 + dont_skip_captcha!
  29 + validates_presence_of :captcha_solution,
  30 + :on => :create, :message => "can't be blank",
  31 + :unless => Proc.new {|record| record.skip_captcha? }
  32 + validate_on_create :must_solve_captcha,
  33 + :unless => Proc.new {|record| record.skip_captcha? }
  34 + end
  35 + def skip_captcha!
  36 + @@skip_captcha = true
  37 + end
  38 + def dont_skip_captcha!
  39 + @@skip_captcha = false
  40 + end
  41 + def skip_captcha?
  42 + @@skip_captcha
  43 + end
  44 + def skipping_captcha(&block)
  45 + skipping_before = skip_captcha?
  46 + skip_captcha!
  47 + yield
  48 + dont_skip_captcha! if skipping_before
  49 + end
  50 + end
  51 + end
  52 +end
  53 +
  54 +ActiveRecord::Base.send(:extend, MathCaptcha::HasCaptcha::ClassMethods)
... ...
vendor/plugins/rails-math-captcha/spec/captcha_spec.rb 0 → 100644
... ... @@ -0,0 +1,49 @@
  1 +require 'lib/math_captcha/captcha'
  2 +require 'base64'
  3 +
  4 +describe Captcha do
  5 + describe "with a random task" do
  6 + before(:each) do
  7 + @captcha = Captcha.new
  8 + end
  9 + it "should have arguments and an operator" do
  10 + @captcha.x.should_not be_nil
  11 + @captcha.y.should_not be_nil
  12 + @captcha.operator.should_not be_nil
  13 + end
  14 + it "should use numbers bigger than zero" do
  15 + @captcha.x.should > 0
  16 + @captcha.y.should > 0
  17 + end
  18 + it "should offer a human readable task" do
  19 + @captcha.task.should =~ /^\d+\s*[\+\-\*]\s*\d+$/
  20 + end
  21 + it "should have a secret to use in forms" do
  22 + @captcha.to_secret.should_not be_nil
  23 + @captcha.to_secret.should_not be_empty
  24 + end
  25 +
  26 + it "should re-use its cipher" do
  27 + @captcha.send(:cipher).should == @captcha.send(:cipher)
  28 + end
  29 +
  30 + it "should have a base64 encoded secret" do
  31 + lambda { Base64.decode64(@captcha.to_secret).should_not be_nil }.should_not raise_error
  32 + end
  33 +
  34 + describe "re-creating another from secret" do
  35 + before(:each) do
  36 + @secret = @captcha.to_secret
  37 + @new_captcha = Captcha.from_secret(@secret)
  38 + end
  39 + it "should have the same arguments and operator" do
  40 + @new_captcha.x.should == @captcha.x
  41 + @new_captcha.y.should == @captcha.y
  42 + @new_captcha.operator.should == @captcha.operator
  43 + end
  44 + it "should have the same string" do
  45 + @new_captcha.task.should == @captcha.task
  46 + end
  47 + end
  48 + end
  49 +end
... ...
vendor/plugins/rails-math-captcha/spec/spec.opts 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +--colour
  2 +--format progress
  3 +--loadby mtime
  4 +--reverse
... ...