Skip to content

Instantly share code, notes, and snippets.

@mindhalt
Created July 5, 2013 14:38
Show Gist options
  • Save mindhalt/5934987 to your computer and use it in GitHub Desktop.
Save mindhalt/5934987 to your computer and use it in GitHub Desktop.
Simple math captcha for Rails Fixed version of http://blog.trikeapps.com/2010/12/20/secure-form-with-math-captcha.html Tested on Rails 3.2.13 and Ruby 2.0.0 P.S. don't forget to include math_captcha.rb to included paths.
require 'math_captcha'
class CarsController < ApplicationController
# GET|POST /order
def order
@item = Item.find(params[:id])
if request.get?
@form = ModellessForm.new
@captcha = MathCaptcha.new
respond_with @item
else
@form = ModellessForm.new(params[:order_car_form])
@captcha = MathCaptcha.decrypt(@form.captcha_secret)
if @order_car_form.valid? and @captcha.correct?(@form.captcha)
else
unless @captcha.correct?(@form.captcha)
@order_car_form.errors[:captcha] << I18n.t(:verification_failed, :scope => [:math_captcha, :errors])
end
@captcha = MathCaptcha.new
respond_with @item
end
end
end
end
require 'ezcrypto'
class MathCaptcha
CIPHER_KEY = "your cipher key"
CIPHER_SALT = "your cipher salt"
NUMBERS = (1..100).to_a
attr_reader :a, :b, :operator
def initialize
@a = NUMBERS.sample
@b = NUMBERS.sample
@operator = [:+, :-].sample
end
def initialize_from(secret)
yml = YAML.load(key.decrypt64(secret))
@a, @b, @operator = yml[:a], yml[:b], yml[:operator]
end
def correct?(value)
result.to_i == value.to_i
end
def encrypt
key.encrypt64 to_yaml
end
def self.decrypt(secret)
result = new
result.initialize_from secret
result
end
def question
"#{@a} #{@operator.to_s} #{@b} = ?"
end
def to_i
result
end
protected
def to_yaml
YAML::dump({
:a => @a,
:b => @b,
:operator => @operator
})
end
private
def key
EzCrypto::Key.with_password CIPHER_KEY, CIPHER_SALT
end
def result
@a.send(@operator, @b)
end
end
class ModellessForm
include ActiveModel::Validations
include ActiveModel::Conversion
attr_accessor :captcha, :captcha_secret
validates :captcha, :numericality => true,
:presence => true
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted?
false
end
end
ru:
math_captcha:
errors:
verification_failed: "неправильный ответ"
<%# using Formtastic gem %>
<%= f.input :captcha, :as => :string, :required => false, :label => @captcha.question, :input_html => { :value => '' } %>
<%= f.input :captcha_secret, :as => :hidden, :input_html => { :value => @captcha.encrypt } %>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment