recaptcha 0.3.6 → 5.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +141 -0
- data/README.md +520 -0
- data/lib/recaptcha.rb +89 -15
- data/lib/recaptcha/adapters/controller_methods.rb +94 -0
- data/lib/recaptcha/adapters/view_methods.rb +26 -0
- data/lib/recaptcha/configuration.rb +34 -24
- data/lib/recaptcha/helpers.rb +322 -0
- data/lib/recaptcha/rails.rb +3 -4
- data/lib/recaptcha/railtie.rb +31 -11
- data/lib/recaptcha/version.rb +3 -1
- data/rails/locales/en.yml +5 -0
- metadata +98 -35
- data/.gitignore +0 -3
- data/CHANGELOG +0 -33
- data/Gemfile +0 -3
- data/README.rdoc +0 -146
- data/Rakefile +0 -9
- data/init.rb +0 -5
- data/lib/recaptcha/client_helper.rb +0 -69
- data/lib/recaptcha/merb.rb +0 -4
- data/lib/recaptcha/verify.rb +0 -75
- data/recaptcha.gemspec +0 -24
- data/test/recaptcha_test.rb +0 -62
- data/test/verify_recaptcha_test.rb +0 -151
data/Rakefile
DELETED
data/init.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
module Recaptcha
|
2
|
-
module ClientHelper
|
3
|
-
# Your public API can be specified in the +options+ hash or preferably
|
4
|
-
# using the Configuration.
|
5
|
-
def recaptcha_tags(options = {})
|
6
|
-
# Default options
|
7
|
-
key = options[:public_key] ||= Recaptcha.configuration.public_key
|
8
|
-
raise RecaptchaError, "No public key specified." unless key
|
9
|
-
error = options[:error] ||= ((defined? flash) ? flash[:recaptcha_error] : "")
|
10
|
-
uri = Recaptcha.configuration.api_server_url(options[:ssl])
|
11
|
-
lang = options[:display] && options[:display][:lang] ? options[:display][:lang].to_sym : ""
|
12
|
-
html = ""
|
13
|
-
if options[:display]
|
14
|
-
html << %{<script type="text/javascript">\n}
|
15
|
-
html << %{ var RecaptchaOptions = #{hash_to_json(options[:display])};\n}
|
16
|
-
html << %{</script>\n}
|
17
|
-
end
|
18
|
-
if options[:ajax]
|
19
|
-
html << <<-EOS
|
20
|
-
<div id="dynamic_recaptcha"></div>
|
21
|
-
<script type="text/javascript">
|
22
|
-
var rc_script_tag = document.createElement('script'),
|
23
|
-
rc_init_func = function(){Recaptcha.create("#{key}", document.getElementById("dynamic_recaptcha")#{',RecaptchaOptions' if options[:display]});}
|
24
|
-
rc_script_tag.src = "#{uri}/js/recaptcha_ajax.js";
|
25
|
-
rc_script_tag.type = 'text/javascript';
|
26
|
-
rc_script_tag.onload = function(){rc_init_func.call();};
|
27
|
-
rc_script_tag.onreadystatechange = function(){
|
28
|
-
if (rc_script_tag.readyState == 'loaded' || rc_script_tag.readyState == 'complete') {rc_init_func.call();}
|
29
|
-
};
|
30
|
-
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(rc_script_tag);
|
31
|
-
</script>
|
32
|
-
EOS
|
33
|
-
else
|
34
|
-
html << %{<script type="text/javascript" src="#{uri}/challenge?k=#{key}}
|
35
|
-
html << %{#{error ? "&error=#{CGI::escape(error)}" : ""}}
|
36
|
-
html << %{#{lang ? "&lang=#{lang}" : ""}"></script>\n}
|
37
|
-
unless options[:noscript] == false
|
38
|
-
html << %{<noscript>\n }
|
39
|
-
html << %{<iframe src="#{uri}/noscript?k=#{key}" }
|
40
|
-
html << %{height="#{options[:iframe_height] ||= 300}" }
|
41
|
-
html << %{width="#{options[:iframe_width] ||= 500}" }
|
42
|
-
html << %{style="border:none;"></iframe><br/>\n }
|
43
|
-
html << %{<textarea name="recaptcha_challenge_field" }
|
44
|
-
html << %{rows="#{options[:textarea_rows] ||= 3}" }
|
45
|
-
html << %{cols="#{options[:textarea_cols] ||= 40}"></textarea>\n }
|
46
|
-
html << %{<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>}
|
47
|
-
html << %{</noscript>\n}
|
48
|
-
end
|
49
|
-
end
|
50
|
-
return (html.respond_to?(:html_safe) && html.html_safe) || html
|
51
|
-
end # recaptcha_tags
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
|
-
def hash_to_json(hash)
|
56
|
-
result = "{"
|
57
|
-
result << hash.map do |k, v|
|
58
|
-
if v.is_a?(Hash)
|
59
|
-
"\"#{k}\": #{hash_to_json(v)}"
|
60
|
-
elsif ! v.is_a?(String) || k.to_s == "callback"
|
61
|
-
"\"#{k}\": #{v}"
|
62
|
-
else
|
63
|
-
"\"#{k}\": \"#{v}\""
|
64
|
-
end
|
65
|
-
end.join(", ")
|
66
|
-
result << "}"
|
67
|
-
end
|
68
|
-
end # ClientHelper
|
69
|
-
end # Recaptcha
|
data/lib/recaptcha/merb.rb
DELETED
data/lib/recaptcha/verify.rb
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
require "uri"
|
2
|
-
module Recaptcha
|
3
|
-
module Verify
|
4
|
-
# Your private API can be specified in the +options+ hash or preferably
|
5
|
-
# using the Configuration.
|
6
|
-
def verify_recaptcha(options = {})
|
7
|
-
if !options.is_a? Hash
|
8
|
-
options = {:model => options}
|
9
|
-
end
|
10
|
-
|
11
|
-
env = options[:env] || ENV['RAILS_ENV']
|
12
|
-
return true if Recaptcha.configuration.skip_verify_env.include? env
|
13
|
-
model = options[:model]
|
14
|
-
attribute = options[:attribute] || :base
|
15
|
-
private_key = options[:private_key] || Recaptcha.configuration.private_key
|
16
|
-
raise RecaptchaError, "No private key specified." unless private_key
|
17
|
-
|
18
|
-
begin
|
19
|
-
recaptcha = nil
|
20
|
-
if(Recaptcha.configuration.proxy)
|
21
|
-
proxy_server = URI.parse(Recaptcha.configuration.proxy)
|
22
|
-
http = Net::HTTP::Proxy(proxy_server.host, proxy_server.port, proxy_server.user, proxy_server.password)
|
23
|
-
else
|
24
|
-
http = Net::HTTP
|
25
|
-
end
|
26
|
-
|
27
|
-
Timeout::timeout(options[:timeout] || 3) do
|
28
|
-
recaptcha = http.post_form(URI.parse(Recaptcha.configuration.verify_url), {
|
29
|
-
"privatekey" => private_key,
|
30
|
-
"remoteip" => request.remote_ip,
|
31
|
-
"challenge" => params[:recaptcha_challenge_field],
|
32
|
-
"response" => params[:recaptcha_response_field]
|
33
|
-
})
|
34
|
-
end
|
35
|
-
answer, error = recaptcha.body.split.map { |s| s.chomp }
|
36
|
-
unless answer == 'true'
|
37
|
-
flash[:recaptcha_error] = if defined?(I18n)
|
38
|
-
I18n.translate("recaptcha.errors.#{error}", {:default => error})
|
39
|
-
else
|
40
|
-
error
|
41
|
-
end
|
42
|
-
|
43
|
-
if model
|
44
|
-
message = "Word verification response is incorrect, please try again."
|
45
|
-
message = I18n.translate('recaptcha.errors.verification_failed', {:default => message}) if defined?(I18n)
|
46
|
-
model.errors.add attribute, options[:message] || message
|
47
|
-
end
|
48
|
-
return false
|
49
|
-
else
|
50
|
-
flash.delete(:recaptcha_error)
|
51
|
-
return true
|
52
|
-
end
|
53
|
-
rescue Timeout::Error
|
54
|
-
if Recaptcha.configuration.handle_timeouts_gracefully
|
55
|
-
flash[:recaptcha_error] = if defined?(I18n)
|
56
|
-
I18n.translate('recaptcha.errors.recaptcha_unreachable', {:default => 'Recaptcha unreachable.'})
|
57
|
-
else
|
58
|
-
'Recaptcha unreachable.'
|
59
|
-
end
|
60
|
-
|
61
|
-
if model
|
62
|
-
message = "Oops, we failed to validate your word verification response. Please try again."
|
63
|
-
message = I18n.translate('recaptcha.errors.recaptcha_unreachable', :default => message) if defined?(I18n)
|
64
|
-
model.errors.add attribute, options[:message] || message
|
65
|
-
end
|
66
|
-
return false
|
67
|
-
else
|
68
|
-
raise RecaptchaError, "Recaptcha unreachable."
|
69
|
-
end
|
70
|
-
rescue Exception => e
|
71
|
-
raise RecaptchaError, e.message, e.backtrace
|
72
|
-
end
|
73
|
-
end # verify_recaptcha
|
74
|
-
end # Verify
|
75
|
-
end # Recaptcha
|
data/recaptcha.gemspec
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "recaptcha/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = "recaptcha"
|
7
|
-
s.version = Recaptcha::VERSION
|
8
|
-
s.authors = ["Jason L Perry"]
|
9
|
-
s.email = ["jasper@ambethia.com"]
|
10
|
-
s.homepage = "http://github.com/ambethia/recaptcha"
|
11
|
-
s.summary = %q{Helpers for the reCAPTCHA API}
|
12
|
-
s.description = %q{This plugin adds helpers for the reCAPTCHA API}
|
13
|
-
|
14
|
-
s.rubyforge_project = "recaptcha"
|
15
|
-
|
16
|
-
s.files = `git ls-files`.split("\n")
|
17
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
-
s.require_paths = ["lib"]
|
19
|
-
|
20
|
-
s.add_development_dependency "mocha"
|
21
|
-
s.add_development_dependency "rake"
|
22
|
-
s.add_development_dependency "activesupport"
|
23
|
-
s.add_development_dependency "i18n"
|
24
|
-
end
|
data/test/recaptcha_test.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'cgi'
|
3
|
-
require File.dirname(File.expand_path(__FILE__)) + '/../lib/recaptcha'
|
4
|
-
|
5
|
-
class RecaptchaClientHelperTest < Test::Unit::TestCase
|
6
|
-
include Recaptcha
|
7
|
-
include Recaptcha::ClientHelper
|
8
|
-
include Recaptcha::Verify
|
9
|
-
|
10
|
-
attr_accessor :session
|
11
|
-
|
12
|
-
def setup
|
13
|
-
@session = {}
|
14
|
-
Recaptcha.configure do |config|
|
15
|
-
config.public_key = '0000000000000000000000000000000000000000'
|
16
|
-
config.private_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_recaptcha_tags
|
21
|
-
# Might as well match something...
|
22
|
-
assert_match /"\/\/www.google.com\/recaptcha\/api\/challenge/, recaptcha_tags
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_ssl_by_default
|
26
|
-
Recaptcha.configuration.use_ssl_by_default = true
|
27
|
-
assert_match /https:\/\/www.google.com\/recaptcha\/api\/challenge/, recaptcha_tags
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_relative_protocol_by_default_without_ssl
|
31
|
-
Recaptcha.configuration.use_ssl_by_default = false
|
32
|
-
assert_match /\/\/www.google.com\/recaptcha\/api\/challenge/, recaptcha_tags(:ssl => false)
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_recaptcha_tags_with_ssl
|
36
|
-
assert_match /https:\/\/www.google.com\/recaptcha\/api\/challenge/, recaptcha_tags(:ssl => true)
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_recaptcha_tags_without_noscript
|
40
|
-
assert_no_match /noscript/, recaptcha_tags(:noscript => false)
|
41
|
-
end
|
42
|
-
|
43
|
-
def test_should_raise_exception_without_public_key
|
44
|
-
assert_raise RecaptchaError do
|
45
|
-
Recaptcha.configuration.public_key = nil
|
46
|
-
recaptcha_tags
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_different_configuration_within_with_configuration_block
|
51
|
-
key = Recaptcha.with_configuration(:public_key => '12345') do
|
52
|
-
Recaptcha.configuration.public_key
|
53
|
-
end
|
54
|
-
|
55
|
-
assert_equal('12345', key)
|
56
|
-
end
|
57
|
-
|
58
|
-
def test_reset_configuration_after_with_configuration_block
|
59
|
-
Recaptcha.with_configuration(:public_key => '12345')
|
60
|
-
assert_equal('0000000000000000000000000000000000000000', Recaptcha.configuration.public_key)
|
61
|
-
end
|
62
|
-
end
|
@@ -1,151 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'rubygems'
|
5
|
-
require 'active_support'
|
6
|
-
require 'active_support/core_ext/string'
|
7
|
-
require 'mocha/setup'
|
8
|
-
require 'i18n'
|
9
|
-
require 'net/http'
|
10
|
-
require File.dirname(File.expand_path(__FILE__)) + '/../lib/recaptcha'
|
11
|
-
|
12
|
-
class RecaptchaVerifyTest < Test::Unit::TestCase
|
13
|
-
def setup
|
14
|
-
Recaptcha.configuration.private_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
15
|
-
@controller = TestController.new
|
16
|
-
@controller.request = stub(:remote_ip => "1.1.1.1")
|
17
|
-
@controller.params = {:recaptcha_challenge_field => "challenge", :recaptcha_response_field => "response"}
|
18
|
-
|
19
|
-
@expected_post_data = {}
|
20
|
-
@expected_post_data["privatekey"] = Recaptcha.configuration.private_key
|
21
|
-
@expected_post_data["remoteip"] = @controller.request.remote_ip
|
22
|
-
@expected_post_data["challenge"] = "challenge"
|
23
|
-
@expected_post_data["response"] = "response"
|
24
|
-
|
25
|
-
@expected_uri = URI.parse(Recaptcha.configuration.verify_url)
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_should_raise_exception_without_private_key
|
29
|
-
assert_raise Recaptcha::RecaptchaError do
|
30
|
-
Recaptcha.configuration.private_key = nil
|
31
|
-
@controller.verify_recaptcha
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_should_return_false_when_key_is_invalid
|
36
|
-
expect_http_post(response_with_body("false\ninvalid-site-private-key"))
|
37
|
-
|
38
|
-
assert !@controller.verify_recaptcha
|
39
|
-
assert_equal "invalid-site-private-key", @controller.flash[:recaptcha_error]
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_returns_true_on_success
|
43
|
-
@controller.flash[:recaptcha_error] = "previous error that should be cleared"
|
44
|
-
expect_http_post(response_with_body("true\n"))
|
45
|
-
|
46
|
-
assert @controller.verify_recaptcha
|
47
|
-
assert_nil @controller.flash[:recaptcha_error]
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_errors_should_be_added_to_model
|
51
|
-
expect_http_post(response_with_body("false\nbad-news"))
|
52
|
-
|
53
|
-
errors = mock
|
54
|
-
errors.expects(:add).with(:base, "Word verification response is incorrect, please try again.")
|
55
|
-
model = mock(:errors => errors)
|
56
|
-
|
57
|
-
assert !@controller.verify_recaptcha(:model => model)
|
58
|
-
assert_equal "bad-news", @controller.flash[:recaptcha_error]
|
59
|
-
end
|
60
|
-
|
61
|
-
def test_returns_true_on_success_with_optional_key
|
62
|
-
@controller.flash[:recaptcha_error] = "previous error that should be cleared"
|
63
|
-
# reset private key
|
64
|
-
@expected_post_data["privatekey"] = 'ADIFFERENTPRIVATEKEYXXXXXXXXXXXXXX'
|
65
|
-
expect_http_post(response_with_body("true\n"))
|
66
|
-
|
67
|
-
assert @controller.verify_recaptcha(:private_key => 'ADIFFERENTPRIVATEKEYXXXXXXXXXXXXXX')
|
68
|
-
assert_nil @controller.flash[:recaptcha_error]
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_timeout
|
72
|
-
expect_http_post(Timeout::Error, :exception => true)
|
73
|
-
assert !@controller.verify_recaptcha()
|
74
|
-
assert_equal "Recaptcha unreachable.", @controller.flash[:recaptcha_error]
|
75
|
-
end
|
76
|
-
|
77
|
-
def test_timeout_when_handle_timeouts_gracefully_disabled
|
78
|
-
Recaptcha.with_configuration(:handle_timeouts_gracefully => false) do
|
79
|
-
expect_http_post(Timeout::Error, :exception => true)
|
80
|
-
assert_raise Recaptcha::RecaptchaError, "Recaptcha unreachable." do
|
81
|
-
assert @controller.verify_recaptcha()
|
82
|
-
end
|
83
|
-
assert_nil @controller.flash[:recaptcha_error]
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def test_message_should_use_i18n
|
88
|
-
I18n.locale = :de
|
89
|
-
verification_failed_translated = "Sicherheitscode konnte nicht verifiziert werden."
|
90
|
-
verification_failed_default = "Word verification response is incorrect, please try again."
|
91
|
-
recaptcha_unreachable_translated = "Netzwerkfehler, bitte versuchen Sie es später erneut."
|
92
|
-
recaptcha_unreachable_default = "Oops, we failed to validate your word verification response. Please try again."
|
93
|
-
|
94
|
-
I18n.expects(:translate).with('recaptcha.errors.bad-news', {:default => 'bad-news'})
|
95
|
-
I18n.expects(:translate).with('recaptcha.errors.recaptcha_unreachable', {:default => 'Recaptcha unreachable.'})
|
96
|
-
|
97
|
-
I18n.expects(:translate).with('recaptcha.errors.verification_failed', :default => verification_failed_default).returns(verification_failed_translated)
|
98
|
-
I18n.expects(:translate).with('recaptcha.errors.recaptcha_unreachable', :default => recaptcha_unreachable_default).returns(recaptcha_unreachable_translated)
|
99
|
-
|
100
|
-
errors = mock
|
101
|
-
errors.expects(:add).with(:base, verification_failed_translated)
|
102
|
-
errors.expects(:add).with(:base, recaptcha_unreachable_translated)
|
103
|
-
model = mock; model.stubs(:errors => errors)
|
104
|
-
|
105
|
-
expect_http_post(response_with_body("false\nbad-news"))
|
106
|
-
@controller.verify_recaptcha(:model => model)
|
107
|
-
|
108
|
-
expect_http_post(Timeout::Error, :exception => true)
|
109
|
-
@controller.verify_recaptcha(:model => model)
|
110
|
-
|
111
|
-
end
|
112
|
-
|
113
|
-
def test_it_translates_api_response_with_i18n
|
114
|
-
api_error_translated = "Bad news, body :("
|
115
|
-
expect_http_post(response_with_body("false\nbad-news"))
|
116
|
-
I18n.expects(:translate).with('recaptcha.errors.bad-news', :default => 'bad-news').returns(api_error_translated)
|
117
|
-
|
118
|
-
assert !@controller.verify_recaptcha
|
119
|
-
assert_equal api_error_translated, @controller.flash[:recaptcha_error]
|
120
|
-
end
|
121
|
-
|
122
|
-
def test_it_fallback_to_api_response_if_i18n_translation_is_missing
|
123
|
-
expect_http_post(response_with_body("false\nbad-news"))
|
124
|
-
|
125
|
-
assert !@controller.verify_recaptcha
|
126
|
-
assert_equal 'bad-news', @controller.flash[:recaptcha_error]
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
class TestController
|
132
|
-
include Recaptcha::Verify
|
133
|
-
attr_accessor :request, :params, :flash
|
134
|
-
|
135
|
-
def initialize
|
136
|
-
@flash = {}
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
def expect_http_post(response, options = {})
|
141
|
-
unless options[:exception]
|
142
|
-
Net::HTTP.expects(:post_form).with(@expected_uri, @expected_post_data).returns(response)
|
143
|
-
else
|
144
|
-
Net::HTTP.expects(:post_form).raises response
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def response_with_body(body)
|
149
|
-
stub(:body => body)
|
150
|
-
end
|
151
|
-
end
|