cure-recaptcha 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5f9b067367260a289398dd9afc46f91c49163d38
4
+ data.tar.gz: bf5581b12a643b557a916daaf4c9c61eafecd500
5
+ SHA512:
6
+ metadata.gz: 40d1386d493d31c6f8781b19c9509220b2823c9fdb93e5966d87385807382edc03c746fb3987451e9ab7659fb0408d076c1ed89aab495b23705c00e532d6cbc0
7
+ data.tar.gz: ba4b195f4c3b123dbe8e7126fa03d80f20c97ec5fcd15ad2d302ff64d44f1a8522c7509193b010c95db469fbeec8704d5f2a2fa2abf0252202e563e89c198ca5
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ rdoc
2
+ pkg
3
+ .ruby-gemset
4
+ .ruby-version
5
+ .bundle
6
+
7
+ .gems
8
+ .rbenv-gemsets
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
data/CHANGELOG ADDED
@@ -0,0 +1,41 @@
1
+ == 0.3.6 / 2012-01-07
2
+
3
+ * Many documentation changes
4
+ * Fixed deprecations in dependencies
5
+ * Protocol relative JS includes
6
+ * Fixes for options hash
7
+ * Fixes for failing tests
8
+
9
+ == 0.3.5 / 2012-05-02
10
+
11
+ * I18n for error messages
12
+ * Rails: delete flash keys if unused
13
+
14
+ == 0.3.4 / 2011-12-13
15
+
16
+ * Rails 3
17
+ * Remove jeweler
18
+
19
+ == 0.2.2 / 2009-09-14
20
+
21
+ * Add a timeout to the validator
22
+ * Give the documentation some love
23
+
24
+ == 0.2.1 / 2009-09-14
25
+
26
+ * Removed Ambethia namespace, and restructured classes a bit
27
+ * Added an example rails app in the example-rails branch
28
+
29
+ == 0.2.0 / 2009-09-12
30
+
31
+ * RecaptchaOptions AJAX API Fix
32
+ * Added 'cucumber' as a test environment to skip
33
+ * Ruby 1.9 compat fixes
34
+ * Added option :message => 'Custom error message' to verify_recaptcha
35
+ * Removed dependency on ActiveRecord constant
36
+ * Add I18n
37
+
38
+ == 0.1.0 / 2008-2-8
39
+
40
+ * 1 major enhancement
41
+ * Initial Gem Release
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,52 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cure-recaptcha (0.4.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activesupport (4.1.8)
10
+ i18n (~> 0.6, >= 0.6.9)
11
+ json (~> 1.7, >= 1.7.7)
12
+ minitest (~> 5.1)
13
+ thread_safe (~> 0.1)
14
+ tzinfo (~> 1.1)
15
+ byebug (3.5.1)
16
+ columnize (~> 0.8)
17
+ debugger-linecache (~> 1.2)
18
+ slop (~> 3.6)
19
+ coderay (1.1.0)
20
+ columnize (0.8.9)
21
+ debugger-linecache (1.2.0)
22
+ i18n (0.6.11)
23
+ json (1.8.1)
24
+ metaclass (0.0.4)
25
+ method_source (0.8.2)
26
+ minitest (5.4.3)
27
+ mocha (1.1.0)
28
+ metaclass (~> 0.0.1)
29
+ pry (0.10.1)
30
+ coderay (~> 1.1.0)
31
+ method_source (~> 0.8.1)
32
+ slop (~> 3.4)
33
+ pry-byebug (2.0.0)
34
+ byebug (~> 3.4)
35
+ pry (~> 0.10)
36
+ rake (10.3.2)
37
+ slop (3.6.0)
38
+ thread_safe (0.3.4)
39
+ tzinfo (1.2.2)
40
+ thread_safe (~> 0.1)
41
+
42
+ PLATFORMS
43
+ ruby
44
+
45
+ DEPENDENCIES
46
+ activesupport
47
+ i18n
48
+ minitest (~> 5.0)
49
+ mocha
50
+ pry-byebug
51
+ rake
52
+ recaptcha!
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2007 Jason L Perry
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,151 @@
1
+ = reCAPTCHA
2
+
3
+ Author:: Jason L Perry (http://ambethia.com)
4
+ Copyright:: Copyright (c) 2007-2013 Jason L Perry
5
+ License:: {MIT}[http://creativecommons.org/licenses/MIT/]
6
+ Info:: http://github.com/ambethia/recaptcha
7
+ Bugs:: http://github.com/ambethia/recaptcha/issues
8
+
9
+ This plugin adds helpers for the {reCAPTCHA API}[https://www.google.com/recaptcha]. In your
10
+ views you can use the +recaptcha_tags+ method to embed the needed javascript,
11
+ and you can validate in your controllers with +verify_recaptcha+ or +verify_recaptcha!+,
12
+ which throws an error on failiure.
13
+
14
+ Beforehand you need to configure Recaptcha with your custom private and public
15
+ key. You may find detailed examples below. Exceptions will be raised if you
16
+ call these methods and the keys can't be found.
17
+
18
+ == Rails Installation
19
+
20
+ reCAPTCHA for Rails > 3.0, add this to your Gemfile:
21
+
22
+ gem "recaptcha", :require => "recaptcha/rails"
23
+
24
+ Rails apps below 3.0 are no longer supported, but you can install an older
25
+ release and view it's README.
26
+
27
+ == Setting up your API Keys
28
+
29
+ There are multiple ways to setup your reCAPTCHA API key once you
30
+ {obtain}[https://www.google.com/recaptcha/admin] a pair.
31
+
32
+ === Recaptcha.configure
33
+
34
+ You may use the block style configuration. The following code could be placed
35
+ into a +config/initializers/recaptcha.rb+ when used in a Rails project.
36
+
37
+ Recaptcha.configure do |config|
38
+ config.public_key = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
39
+ config.private_key = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
40
+ # Uncomment the following line if you are using a proxy server:
41
+ # config.proxy = 'http://myproxy.com.au:8080'
42
+ # Uncomment if you want to use the newer version of the API,
43
+ # only works for versions >= 0.3.7:
44
+ # config.api_version = 'v2'
45
+ end
46
+
47
+ This way, you may also set additional options to fit recaptcha into your
48
+ deployment environment.
49
+
50
+ == Recaptcha#with_configuration
51
+
52
+ If you want to temporarily overwrite the configuration you set with `Recaptcha.configure` (when testing, for example), you can use a `Recaptcha#with_configuration` block:
53
+
54
+ Recaptcha.with_configuration(:public_key => '12345') do
55
+ # Do stuff with the overwritten public_key.
56
+ end
57
+
58
+ === Heroku & Shell environment
59
+
60
+ Or, you can keep your keys out of your code base by exporting the following
61
+ environment variables. You might do this in the .profile/rc, or equivalent for
62
+ the user running your application. This would also be the preffered method
63
+ in an Heroku deployment.
64
+
65
+ export RECAPTCHA_PUBLIC_KEY = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
66
+ export RECAPTCHA_PRIVATE_KEY = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
67
+
68
+ === Per call
69
+
70
+ You can also pass in your keys as options at runtime, for example:
71
+
72
+ recaptcha_tags :public_key => '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
73
+
74
+ and later,
75
+
76
+ verify_recaptcha :private_key => '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
77
+
78
+ This option might be useful, if the same code base is used for multiple
79
+ reCAPTCHA setups.
80
+
81
+ == To use 'recaptcha'
82
+
83
+ Add +recaptcha_tags+ to each form you want to protect. Place it where you want the recaptcha widget to appear.
84
+
85
+ Example:
86
+
87
+ <%= form_for @foo do |f| %>
88
+ # ... additional lines truncated for brevity ...
89
+ <%= recaptcha_tags %>
90
+ # ... additional lines truncated for brevity ...
91
+ <% end %>
92
+
93
+ And, add +verify_recaptcha+ logic to each form action that you've protected.
94
+
95
+ === +recaptcha_tags+
96
+
97
+ Some of the options available:
98
+
99
+ <tt>:ssl</tt>:: Uses secure http for captcha widget (default +false+, but can be changed by setting +config.use_ssl_by_default+)
100
+ <tt>:noscript</tt>:: Include <noscript> content (default +true+)
101
+ <tt>:display</tt>:: Takes a hash containing the +theme+ and +tabindex+ options per the API. (default +nil+), options: 'red', 'white', 'blackglass', 'clean', 'custom'
102
+ <tt>:ajax</tt>:: Render the dynamic AJAX captcha per the API. (default +false+)
103
+ <tt>:public_key</tt>:: Your public API key, takes precedence over the ENV variable (default +nil+)
104
+ <tt>:error</tt>:: Override the error code returned from the reCAPTCHA API (default +nil+)
105
+
106
+ You can also override the html attributes for the sizes of the generated +textarea+ and +iframe+
107
+ elements, if CSS isn't your thing. Inspect the source of +recaptcha_tags+ to see these options.
108
+
109
+ === +verify_recaptcha+
110
+
111
+ This method returns +true+ or +false+ after processing the parameters from the reCAPTCHA widget. Why
112
+ isn't this a model validation? Because that violates MVC. You can use it like this, or how ever you
113
+ like. Passing in the ActiveRecord object is optional, if you do--and the captcha fails to verify--an
114
+ error will be added to the object for you to use.
115
+
116
+ Some of the options available:
117
+
118
+ <tt>:model</tt>:: Model to set errors
119
+ <tt>:attribute</tt>:: Model attribute to receive errors (default :base)
120
+ <tt>:message</tt>:: Custom error message
121
+ <tt>:private_key</tt>:: Your private API key, takes precedence over the ENV variable (default +nil+).
122
+ <tt>:timeout</tt>:: The number of seconds to wait for reCAPTCHA servers before give up. (default +3+)
123
+
124
+ respond_to do |format|
125
+ if verify_recaptcha(:model => @post, :message => "Oh! It's error with reCAPTCHA!") && @post.save
126
+ # ...
127
+ else
128
+ # ...
129
+ end
130
+ end
131
+
132
+ == I18n support
133
+ reCAPTCHA passes two types of error explanation to a linked model. It will use the I18n gem
134
+ to translate the default error message if I18n is available. To customize the messages to your locale,
135
+ add these keys to your I18n backend:
136
+
137
+ <tt>recaptcha.errors.verification_failed</tt>:: error message displayed if the captcha words didn't match
138
+ <tt>recaptcha.errors.recaptcha_unreachable</tt>:: displayed if a timeout error occured while attempting to verify the captcha
139
+
140
+ Also you can translate API response errors to human friendly by adding translations to the locale (+config/locales/en.yml+):
141
+
142
+ en:
143
+ recaptcha:
144
+ errors:
145
+ incorrect-captcha-sol: 'Fail'
146
+
147
+ == TODO
148
+ * Remove Rails/ActionController dependencies
149
+ * Framework agnostic
150
+ * Add some helpers to use in before_filter and what not
151
+ * Better documentation
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.test_files = FileList['test/*_test.rb']
6
+ end
7
+
8
+ task :default => :test
data/init.rb ADDED
@@ -0,0 +1,5 @@
1
+ # Rails plugin initialization.
2
+ # You can also install it as a gem:
3
+ # config.gem "ambethia-recaptcha", :lib => "recaptcha/rails", :source => "http://gems.github.com"
4
+
5
+ require 'recaptcha/rails'
data/lib/recaptcha.rb ADDED
@@ -0,0 +1,66 @@
1
+ require 'recaptcha/configuration'
2
+ require 'recaptcha/client_helper'
3
+ require 'recaptcha/verify'
4
+
5
+ module Recaptcha
6
+ CONFIG =
7
+ {
8
+ 'v1' => {
9
+ 'server_url' => '//www.google.com/recaptcha/api',
10
+ 'secure_server_url' => 'https://www.google.com/recaptcha/api',
11
+ 'verify_url' => 'http://www.google.com/recaptcha/api/verify'
12
+ },
13
+
14
+ 'v2' => {
15
+ 'server_url' => '//www.google.com/recaptcha/api.js',
16
+ 'secure_server_url' => 'https://www.google.com/recaptcha/api.js',
17
+ 'verify_url' => 'https://www.google.com/recaptcha/api/siteverify'
18
+ }
19
+ }
20
+
21
+ RECAPTCHA_API_VERSION = 'v2'
22
+ USE_SSL_BY_DEFAULT = false
23
+ HANDLE_TIMEOUTS_GRACEFULLY = true
24
+ SKIP_VERIFY_ENV = ['test', 'cucumber']
25
+
26
+ # Gives access to the current Configuration.
27
+ def self.configuration
28
+ @configuration ||= Configuration.new
29
+ end
30
+
31
+ # Allows easy setting of multiple configuration options. See Configuration
32
+ # for all available options.
33
+ #--
34
+ # The temp assignment is only used to get a nicer rdoc. Feel free to remove
35
+ # this hack.
36
+ #++
37
+ def self.configure
38
+ config = configuration
39
+ yield(config)
40
+ end
41
+
42
+ def self.with_configuration(config)
43
+ original_config = {}
44
+
45
+ config.each do |key, value|
46
+ original_config[key] = configuration.send(key)
47
+ configuration.send("#{key}=", value)
48
+ end
49
+
50
+ result = yield if block_given?
51
+
52
+ original_config.each { |key, value| configuration.send("#{key}=", value) }
53
+ result
54
+ end
55
+
56
+ class RecaptchaError < StandardError
57
+ end
58
+
59
+ class VerifyError < RecaptchaError
60
+ end
61
+
62
+ end
63
+
64
+ if defined?(Rails)
65
+ require 'recaptcha/rails'
66
+ end
@@ -0,0 +1,121 @@
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
+ return v1_tags(options) if Recaptcha.configuration.v1?
7
+ return v2_tags(options) if Recaptcha.configuration.v2?
8
+ end # recaptcha_tags
9
+
10
+ def v1_tags(options)
11
+ # Default options
12
+ key = options[:public_key] ||= Recaptcha.configuration.public_key
13
+ raise RecaptchaError, "No public key specified." unless key
14
+ error = options[:error] ||= ((defined? flash) ? flash[:recaptcha_error] : "")
15
+ uri = Recaptcha.configuration.api_server_url(options[:ssl])
16
+ lang = options[:display] && options[:display][:lang] ? options[:display][:lang].to_sym : ""
17
+ html = ""
18
+ if options[:display]
19
+ html << %{<script type="text/javascript">\n}
20
+ html << %{ var RecaptchaOptions = #{hash_to_json(options[:display])};\n}
21
+ html << %{</script>\n}
22
+ end
23
+ if options[:ajax]
24
+ if options[:display] && options[:display][:custom_theme_widget]
25
+ widget = options[:display][:custom_theme_widget]
26
+ else
27
+ widget = "dynamic_recaptcha"
28
+ html << <<-EOS
29
+ <div id="#{widget}"></div>
30
+ EOS
31
+ end
32
+ html << <<-EOS
33
+ <script type="text/javascript">
34
+ var rc_script_tag = document.createElement('script'),
35
+ rc_init_func = function(){Recaptcha.create("#{key}", document.getElementById("#{widget}")#{',RecaptchaOptions' if options[:display]});}
36
+ rc_script_tag.src = "#{uri}/js/recaptcha_ajax.js";
37
+ rc_script_tag.type = 'text/javascript';
38
+ rc_script_tag.onload = function(){rc_init_func.call();};
39
+ rc_script_tag.onreadystatechange = function(){
40
+ if (rc_script_tag.readyState == 'loaded' || rc_script_tag.readyState == 'complete') {rc_init_func.call();}
41
+ };
42
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(rc_script_tag);
43
+ </script>
44
+ EOS
45
+ else
46
+ html << %{<script type="text/javascript" src="#{uri}/challenge?k=#{key}}
47
+ html << %{#{error ? "&amp;error=#{CGI::escape(error)}" : ""}}
48
+ html << %{#{lang ? "&amp;lang=#{lang}" : ""}"></script>\n}
49
+ unless options[:noscript] == false
50
+ html << %{<noscript>\n }
51
+ html << %{<iframe src="#{uri}/noscript?k=#{key}" }
52
+ html << %{height="#{options[:iframe_height] ||= 300}" }
53
+ html << %{width="#{options[:iframe_width] ||= 500}" }
54
+ html << %{style="border:none;"></iframe><br/>\n }
55
+ html << %{<textarea name="recaptcha_challenge_field" }
56
+ html << %{rows="#{options[:textarea_rows] ||= 3}" }
57
+ html << %{cols="#{options[:textarea_cols] ||= 40}"></textarea>\n }
58
+ html << %{<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>}
59
+ html << %{</noscript>\n}
60
+ end
61
+ end
62
+ return (html.respond_to?(:html_safe) && html.html_safe) || html
63
+ end
64
+
65
+ def v2_tags(options)
66
+ key = options[:public_key] ||= Recaptcha.configuration.public_key
67
+ raise RecaptchaError, "No public key specified." unless key
68
+ error = options[:error] ||= ((defined? flash) ? flash[:recaptcha_error] : "")
69
+ uri = Recaptcha.configuration.api_server_url(options[:ssl])
70
+ uri += "?hl=#{options[:hl]}" unless options[:hl].blank?
71
+
72
+ v2_options = options.slice(:theme, :type, :callback).map {|k,v| %{data-#{k}="#{v}"} }.join(" ")
73
+
74
+ html = ""
75
+ html << %{<script src="#{uri}" async defer></script>\n}
76
+ html << %{<div class="g-recaptcha" data-sitekey="#{key}" #{v2_options}></div>\n}
77
+
78
+ unless options[:noscript] == false
79
+ fallback_uri = "#{uri.chomp('.js')}/fallback?k=#{key}"
80
+ html << %{<noscript>}
81
+ html << %{<div style="width: 302px; height: 352px;">}
82
+ html << %{ <div style="width: 302px; height: 352px; position: relative;">}
83
+ html << %{ <div style="width: 302px; height: 352px; position: absolute;">}
84
+ html << %{ <iframe src="#{fallback_uri}"}
85
+ html << %{ frameborder="0" scrolling="no"}
86
+ html << %{ style="width: 302px; height:352px; border-style: none;">}
87
+ html << %{ </iframe>}
88
+ html << %{ </div>}
89
+ html << %{ <div style="width: 250px; height: 80px; position: absolute; border-style: none; }
90
+ html << %{ bottom: 21px; left: 25px; margin: 0px; padding: 0px; right: 25px;">}
91
+ html << %{ <textarea id="g-recaptcha-response" name="g-recaptcha-response" }
92
+ html << %{ class="g-recaptcha-response" }
93
+ html << %{ style="width: 250px; height: 80px; border: 1px solid #c1c1c1; }
94
+ html << %{ margin: 0px; padding: 0px; resize: none;" value=""> }
95
+ html << %{ </textarea>}
96
+ html << %{ </div>}
97
+ html << %{ </div>}
98
+ html << %{ </div>}
99
+ html << %{</noscript>}
100
+ end
101
+
102
+ return (html.respond_to?(:html_safe) && html.html_safe) || html
103
+ end
104
+
105
+ private
106
+
107
+ def hash_to_json(hash)
108
+ result = "{"
109
+ result << hash.map do |k, v|
110
+ if v.is_a?(Hash)
111
+ "\"#{k}\": #{hash_to_json(v)}"
112
+ elsif ! v.is_a?(String) || k.to_s == "callback"
113
+ "\"#{k}\": #{v}"
114
+ else
115
+ "\"#{k}\": \"#{v}\""
116
+ end
117
+ end.join(", ")
118
+ result << "}"
119
+ end
120
+ end # ClientHelper
121
+ end # Recaptcha
@@ -0,0 +1,74 @@
1
+ module Recaptcha
2
+ # This class enables detailed configuration of the recaptcha services.
3
+ #
4
+ # By calling
5
+ #
6
+ # Recaptcha.configuration # => instance of Recaptcha::Configuration
7
+ #
8
+ # or
9
+ # Recaptcha.configure do |config|
10
+ # config # => instance of Recaptcha::Configuration
11
+ # end
12
+ #
13
+ # you are able to perform configuration updates.
14
+ #
15
+ # Your are able to customize all attributes listed below. All values have
16
+ # sensitive default and will very likely not need to be changed.
17
+ #
18
+ # Please note that the public and private key for the reCAPTCHA API Access
19
+ # have no useful default value. The keys may be set via the Shell enviroment
20
+ # or using this configuration. Settings within this configuration always take
21
+ # precedence.
22
+ #
23
+ # Setting the keys with this Configuration
24
+ #
25
+ # Recaptcha.configure do |config|
26
+ # config.public_key = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
27
+ # config.private_key = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
28
+ # end
29
+ #
30
+ class Configuration
31
+ attr_accessor :api_version,
32
+ :skip_verify_env,
33
+ :private_key,
34
+ :public_key,
35
+ :proxy,
36
+ :handle_timeouts_gracefully,
37
+ :use_ssl_by_default
38
+
39
+ def initialize #:nodoc:
40
+ @api_version = RECAPTCHA_API_VERSION
41
+ @skip_verify_env = SKIP_VERIFY_ENV
42
+ @handle_timeouts_gracefully = HANDLE_TIMEOUTS_GRACEFULLY
43
+ @use_ssl_by_default = USE_SSL_BY_DEFAULT
44
+
45
+ @private_key = ENV['RECAPTCHA_PRIVATE_KEY']
46
+ @public_key = ENV['RECAPTCHA_PUBLIC_KEY']
47
+ end
48
+
49
+ def api_server_url(ssl = nil) #:nodoc:
50
+ ssl = use_ssl_by_default if ssl.nil?
51
+ ssl ? ssl_api_server_url : nonssl_api_server_url
52
+ end
53
+
54
+ def nonssl_api_server_url
55
+ CONFIG[@api_version]['server_url']
56
+ end
57
+
58
+ def ssl_api_server_url
59
+ CONFIG[@api_version]['secure_server_url']
60
+ end
61
+
62
+ def verify_url
63
+ CONFIG[@api_version]['verify_url']
64
+ end
65
+
66
+ def v1?
67
+ @api_version == 'v1'
68
+ end
69
+
70
+ def v2?
71
+ @api_version == 'v2'
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,4 @@
1
+ require 'recaptcha'
2
+
3
+ Merb::GlobalHelpers.send(:include, Recaptcha::ClientHelper)
4
+ Merb::Controller.send(:include, Recaptcha::Verify)
@@ -0,0 +1,5 @@
1
+ require 'net/http'
2
+ require 'recaptcha'
3
+
4
+ ActionView::Base.send(:include, Recaptcha::ClientHelper)
5
+ ActionController::Base.send(:include, Recaptcha::Verify)
@@ -0,0 +1,15 @@
1
+ require 'net/http'
2
+ require 'recaptcha'
3
+ module Rails
4
+ module Recaptcha
5
+ class Railtie < Rails::Railtie
6
+ initializer "setup config" do
7
+ begin
8
+ ActionView::Base.send(:include, ::Recaptcha::ClientHelper)
9
+ ActionController::Base.send(:include, ::Recaptcha::Verify)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,117 @@
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
+ options = {:model => options} unless options.is_a? Hash
8
+
9
+ env_options = options[:env] || ENV['RAILS_ENV']
10
+ return true if Recaptcha.configuration.skip_verify_env.include? env_options
11
+ model = options[:model]
12
+ attribute = options[:attribute] || :base
13
+ private_key = options[:private_key] || Recaptcha.configuration.private_key
14
+ raise RecaptchaError, "No private key specified." unless private_key
15
+
16
+ begin
17
+ recaptcha = nil
18
+ if(Recaptcha.configuration.proxy)
19
+ proxy_server = URI.parse(Recaptcha.configuration.proxy)
20
+ http = Net::HTTP::Proxy(proxy_server.host, proxy_server.port, proxy_server.user, proxy_server.password)
21
+ else
22
+ http = Net::HTTP
23
+ end
24
+
25
+ # env['REMOTE_ADDR'] to retrieve IP for Grape API
26
+ remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR'])
27
+ if Recaptcha.configuration.v1?
28
+ verify_hash = {
29
+ "privatekey" => private_key,
30
+ "remoteip" => remote_ip,
31
+ "challenge" => params[:recaptcha_challenge_field],
32
+ "response" => params[:recaptcha_response_field]
33
+ }
34
+ Timeout::timeout(options[:timeout] || 3) do
35
+ recaptcha = http.post_form(URI.parse(Recaptcha.configuration.verify_url), verify_hash)
36
+ end
37
+ answer, error = recaptcha.body.split.map { |s| s.chomp }
38
+ end
39
+
40
+ if Recaptcha.configuration.v2?
41
+ verify_hash = {
42
+ "secret" => private_key,
43
+ "remoteip" => remote_ip,
44
+ "response" => params['g-recaptcha-response']
45
+ }
46
+
47
+ Timeout::timeout(options[:timeout] || 3) do
48
+ uri = URI.parse(Recaptcha.configuration.verify_url + '?' + verify_hash.to_query)
49
+ http_instance = http.new(uri.host, uri.port)
50
+ if uri.port==443
51
+ http_instance.use_ssl =
52
+ http_instance.verify_mode = OpenSSL::SSL::VERIFY_NONE
53
+ end
54
+ request = Net::HTTP::Get.new(uri.request_uri)
55
+ recaptcha = http_instance.request(request)
56
+ end
57
+ #answer, error = JSON.parse(recaptcha.body).values
58
+ answer = JSON.parse(recaptcha.body)['success']
59
+ if answer.to_s != 'true'
60
+ error = true
61
+ else
62
+ error = false
63
+ end
64
+ end
65
+
66
+ unless answer.to_s == 'true'
67
+ error = 'verification_failed' if error && Recaptcha.configuration.v2?
68
+ if request_in_html_format?
69
+ flash[:recaptcha_error] = if defined?(I18n)
70
+ I18n.translate("recaptcha.errors.#{error}", {:default => error})
71
+ else
72
+ error
73
+ end
74
+ end
75
+
76
+ if model
77
+ message = "Word verification response is incorrect, please try again."
78
+ message = I18n.translate('recaptcha.errors.verification_failed', {:default => message}) if defined?(I18n)
79
+ model.errors.add attribute, options[:message] || message
80
+ end
81
+ return false
82
+ else
83
+ flash.delete(:recaptcha_error) if request_in_html_format?
84
+ return true
85
+ end
86
+ rescue Timeout::Error
87
+ if Recaptcha.configuration.handle_timeouts_gracefully
88
+ if request_in_html_format?
89
+ flash[:recaptcha_error] = if defined?(I18n)
90
+ I18n.translate('recaptcha.errors.recaptcha_unreachable', {:default => 'Recaptcha unreachable.'})
91
+ else
92
+ 'Recaptcha unreachable.'
93
+ end
94
+ end
95
+
96
+ if model
97
+ message = "Oops, we failed to validate your word verification response. Please try again."
98
+ message = I18n.translate('recaptcha.errors.recaptcha_unreachable', :default => message) if defined?(I18n)
99
+ model.errors.add attribute, options[:message] || message
100
+ end
101
+ return false
102
+ else
103
+ raise RecaptchaError, "Recaptcha unreachable."
104
+ end
105
+ rescue Exception => e
106
+ raise RecaptchaError, e.message, e.backtrace
107
+ end
108
+ end # verify_recaptcha
109
+
110
+ def request_in_html_format?
111
+ request.respond_to?(:format) && request.format == :html && respond_to?(:flash)
112
+ end
113
+ def verify_recaptcha!(options = {})
114
+ verify_recaptcha(options) or raise VerifyError
115
+ end #verify_recaptcha!
116
+ end # Verify
117
+ end # Recaptcha
@@ -0,0 +1,3 @@
1
+ module Recaptcha
2
+ VERSION = "0.4.1"
3
+ end
data/recaptcha.gemspec ADDED
@@ -0,0 +1,26 @@
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 = "cure-recaptcha"
7
+ s.version = Recaptcha::VERSION
8
+ s.authors = ["Ward Vandewege"]
9
+ s.email = ["ward@curoverse.com"]
10
+ s.homepage = "http://github.com/cure/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 = "cure-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
+ s.add_development_dependency "minitest", "~> 5.0"
25
+ s.add_development_dependency "pry-byebug"
26
+ end
@@ -0,0 +1,44 @@
1
+ require 'minitest/autorun'
2
+ require 'cgi'
3
+ require File.dirname(File.expand_path(__FILE__)) + '/../lib/recaptcha'
4
+
5
+ class RecaptchaConfigurationTest < Minitest::Test
6
+ include Recaptcha
7
+ include Recaptcha::ClientHelper
8
+ include Recaptcha::Verify
9
+
10
+ attr_accessor :session
11
+
12
+ def setup
13
+ @session = {}
14
+ @nonssl_api_server_url = Regexp.new(Regexp.quote(Recaptcha.configuration.nonssl_api_server_url) + '(.*)')
15
+ @ssl_api_server_url = Regexp.new(Regexp.quote(Recaptcha.configuration.ssl_api_server_url) + '(.*)')
16
+ Recaptcha.configure do |config|
17
+ config.public_key = '0000000000000000000000000000000000000000'
18
+ config.private_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
19
+ config.api_version = 'v2'
20
+ end
21
+ end
22
+
23
+ def test_recaptcha_api_version_default
24
+ assert_equal(Recaptcha.configuration.api_version, Recaptcha::RECAPTCHA_API_VERSION)
25
+ end
26
+
27
+ def test_v2_with_v2_api?
28
+ assert Recaptcha.configuration.v2?
29
+ refute Recaptcha.configuration.v1?
30
+ end
31
+
32
+ def test_different_configuration_within_with_configuration_block
33
+ key = Recaptcha.with_configuration(:public_key => '12345') do
34
+ Recaptcha.configuration.public_key
35
+ end
36
+
37
+ assert_equal('12345', key)
38
+ end
39
+
40
+ def test_reset_configuration_after_with_configuration_block
41
+ Recaptcha.with_configuration(:public_key => '12345')
42
+ assert_equal('0000000000000000000000000000000000000000', Recaptcha.configuration.public_key)
43
+ end
44
+ end
@@ -0,0 +1,54 @@
1
+ require 'minitest/autorun'
2
+ require 'cgi'
3
+ require File.dirname(File.expand_path(__FILE__)) + '/../lib/recaptcha'
4
+
5
+ class RecaptchaClientHelperTest < Minitest::Test
6
+ include Recaptcha
7
+ include Recaptcha::ClientHelper
8
+ include Recaptcha::Verify
9
+
10
+ attr_accessor :session
11
+
12
+ def setup
13
+ @session = {}
14
+ @nonssl_api_server_url = Regexp.new(Regexp.quote(Recaptcha.configuration.nonssl_api_server_url) + '(.*)')
15
+ @ssl_api_server_url = Regexp.new(Regexp.quote(Recaptcha.configuration.ssl_api_server_url) + '(.*)')
16
+ Recaptcha.configure do |config|
17
+ config.public_key = '0000000000000000000000000000000000000000'
18
+ config.private_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
19
+ end
20
+ end
21
+
22
+ def test_recaptcha_tags_v2
23
+ Recaptcha.configuration.api_version = 'v2'
24
+ # match a v2 only tag
25
+ assert_match /data-sitekey/, recaptcha_tags
26
+ # refute a v1 only tag
27
+ refute_match /\/challenge\?/, recaptcha_tags
28
+ end
29
+
30
+ def test_ssl_by_default
31
+ Recaptcha.configuration.use_ssl_by_default = true
32
+ assert_match @ssl_api_server_url, recaptcha_tags
33
+ end
34
+
35
+ def test_relative_protocol_by_default_without_ssl
36
+ Recaptcha.configuration.use_ssl_by_default = false
37
+ assert_match @nonssl_api_server_url, recaptcha_tags(:ssl => false)
38
+ end
39
+
40
+ def test_recaptcha_tags_with_ssl
41
+ assert_match @ssl_api_server_url, recaptcha_tags(:ssl => true)
42
+ end
43
+
44
+ def test_recaptcha_tags_without_noscript
45
+ refute_match /noscript/, recaptcha_tags(:noscript => false)
46
+ end
47
+
48
+ def test_should_raise_exception_without_public_key
49
+ assert_raises RecaptchaError do
50
+ Recaptcha.configuration.public_key = nil
51
+ recaptcha_tags
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,35 @@
1
+ require 'minitest/autorun'
2
+ require 'cgi'
3
+ require File.dirname(File.expand_path(__FILE__)) + '/../lib/recaptcha'
4
+
5
+ class RecaptchaV1Test < Minitest::Test
6
+ include Recaptcha
7
+ include Recaptcha::ClientHelper
8
+ include Recaptcha::Verify
9
+
10
+ attr_accessor :session
11
+
12
+ def setup
13
+ @session = {}
14
+ @nonssl_api_server_url = Regexp.new(Regexp.quote(Recaptcha.configuration.nonssl_api_server_url) + '(.*)')
15
+ @ssl_api_server_url = Regexp.new(Regexp.quote(Recaptcha.configuration.ssl_api_server_url) + '(.*)')
16
+ Recaptcha.configure do |config|
17
+ config.public_key = '0000000000000000000000000000000000000000'
18
+ config.private_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
19
+ config.api_version = 'v1'
20
+ end
21
+ end
22
+
23
+ def test_v1_with_v1_api?
24
+ assert Recaptcha.configuration.v1?
25
+ refute Recaptcha.configuration.v2?
26
+ end
27
+
28
+ def test_recaptcah_tags_v1
29
+ Recaptcha.configuration.api_version = 'v1'
30
+ # match a v1 only tag
31
+ assert_match /\/challenge\?/, recaptcha_tags
32
+ # refute a v2 only tag
33
+ refute_match /data-sitekey/, recaptcha_tags
34
+ end
35
+ end
@@ -0,0 +1,191 @@
1
+ # coding: utf-8
2
+
3
+ require 'minitest/autorun'
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 < Minitest::Test
13
+ def setup
14
+ Recaptcha.configuration.private_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
15
+ @controller = TestController.new
16
+ @controller.request = stub(:remote_ip => "1.1.1.1", format: :html)
17
+
18
+ @expected_post_data = {}
19
+ @expected_post_data["remoteip"] = @controller.request.remote_ip
20
+ @expected_post_data["response"] = "response"
21
+
22
+ if Recaptcha.configuration.v1?
23
+ @controller.params = {:recaptcha_challenge_field => "challenge", :recaptcha_response_field => "response"}
24
+ @expected_post_data["privatekey"] = Recaptcha.configuration.private_key
25
+ @expected_post_data["challenge"] = "challenge"
26
+ end
27
+
28
+ if Recaptcha.configuration.v2?
29
+ @controller.params = {:recaptcha_response_field => "response"}
30
+ @expected_post_data["secret"] = Recaptcha.configuration.private_key
31
+ end
32
+
33
+ @expected_uri = URI.parse(Recaptcha.configuration.verify_url)
34
+ end
35
+
36
+ def test_should_raise_exception_when_calling_bang_method
37
+ @controller.expects(:verify_recaptcha).returns(false)
38
+
39
+ assert_raises Recaptcha::VerifyError do
40
+ @controller.verify_recaptcha!
41
+ end
42
+ end
43
+
44
+ def test_should_return_whatever_verify_method_returns_when_using_bang_method
45
+ @controller.expects(:verify_recaptcha).returns(:foo)
46
+
47
+ assert_equal :foo, @controller.verify_recaptcha!
48
+ end
49
+
50
+ def test_should_raise_exception_without_private_key
51
+ skip
52
+ assert_raises Recaptcha::RecaptchaError do
53
+ Recaptcha.configuration.private_key = nil
54
+ @controller.verify_recaptcha
55
+ end
56
+ end
57
+
58
+ def test_should_return_false_when_key_is_invalid
59
+ skip
60
+ expect_http_post(response_with_body("false\ninvalid-site-private-key"))
61
+
62
+ assert !@controller.verify_recaptcha
63
+ assert_equal "invalid-site-private-key", @controller.flash[:recaptcha_error]
64
+ end
65
+
66
+ def test_returns_true_on_success
67
+ skip
68
+ @controller.flash[:recaptcha_error] = "previous error that should be cleared"
69
+ expect_http_post(response_with_body("true\n"))
70
+
71
+ assert @controller.verify_recaptcha
72
+ assert_nil @controller.flash[:recaptcha_error]
73
+ end
74
+
75
+ def test_errors_should_be_added_to_model
76
+ skip
77
+ expect_http_post(response_with_body("false\nbad-news"))
78
+
79
+ errors = mock
80
+ errors.expects(:add).with(:base, "Word verification response is incorrect, please try again.")
81
+ model = mock(:errors => errors)
82
+
83
+ assert !@controller.verify_recaptcha(:model => model)
84
+ assert_equal "bad-news", @controller.flash[:recaptcha_error]
85
+ end
86
+
87
+ def test_returns_true_on_success_with_optional_key
88
+ skip
89
+ @controller.flash[:recaptcha_error] = "previous error that should be cleared"
90
+ # reset private key
91
+ @expected_post_data["privatekey"] = 'ADIFFERENTPRIVATEKEYXXXXXXXXXXXXXX'
92
+ expect_http_post(response_with_body("true\n"))
93
+
94
+ assert @controller.verify_recaptcha(:private_key => 'ADIFFERENTPRIVATEKEYXXXXXXXXXXXXXX')
95
+ assert_nil @controller.flash[:recaptcha_error]
96
+ end
97
+
98
+ def test_timeout
99
+ skip
100
+ expect_http_post(Timeout::Error, :exception => true)
101
+ assert !@controller.verify_recaptcha()
102
+ assert_equal "Recaptcha unreachable.", @controller.flash[:recaptcha_error]
103
+ end
104
+
105
+ def test_timeout_when_handle_timeouts_gracefully_disabled
106
+ skip
107
+ Recaptcha.with_configuration(:handle_timeouts_gracefully => false) do
108
+ expect_http_post(Timeout::Error, :exception => true)
109
+ assert_raises Recaptcha::RecaptchaError, "Recaptcha unreachable." do
110
+ assert @controller.verify_recaptcha()
111
+ end
112
+ assert_nil @controller.flash[:recaptcha_error]
113
+ end
114
+ end
115
+
116
+ def test_message_should_use_i18n
117
+ skip
118
+ I18n.locale = :de
119
+ verification_failed_translated = "Sicherheitscode konnte nicht verifiziert werden."
120
+ verification_failed_default = "Word verification response is incorrect, please try again."
121
+ recaptcha_unreachable_translated = "Netzwerkfehler, bitte versuchen Sie es später erneut."
122
+ recaptcha_unreachable_default = "Oops, we failed to validate your word verification response. Please try again."
123
+
124
+ I18n.expects(:translate).with('recaptcha.errors.bad-news', {:default => 'bad-news'})
125
+ I18n.expects(:translate).with('recaptcha.errors.recaptcha_unreachable', {:default => 'Recaptcha unreachable.'})
126
+
127
+ I18n.expects(:translate).with('recaptcha.errors.verification_failed', :default => verification_failed_default).returns(verification_failed_translated)
128
+ I18n.expects(:translate).with('recaptcha.errors.recaptcha_unreachable', :default => recaptcha_unreachable_default).returns(recaptcha_unreachable_translated)
129
+
130
+ errors = mock
131
+ errors.expects(:add).with(:base, verification_failed_translated)
132
+ errors.expects(:add).with(:base, recaptcha_unreachable_translated)
133
+ model = mock; model.stubs(:errors => errors)
134
+
135
+ expect_http_post(response_with_body("false\nbad-news"))
136
+ @controller.verify_recaptcha(:model => model)
137
+
138
+ expect_http_post(Timeout::Error, :exception => true)
139
+ @controller.verify_recaptcha(:model => model)
140
+
141
+ end
142
+
143
+ def test_it_translates_api_response_with_i18n
144
+ skip
145
+ api_error_translated = "Bad news, body :("
146
+ expect_http_post(response_with_body("false\nbad-news"))
147
+ I18n.expects(:translate).with('recaptcha.errors.bad-news', :default => 'bad-news').returns(api_error_translated)
148
+
149
+ assert !@controller.verify_recaptcha
150
+ assert_equal api_error_translated, @controller.flash[:recaptcha_error]
151
+ end
152
+
153
+ def test_it_fallback_to_api_response_if_i18n_translation_is_missing
154
+ skip
155
+ expect_http_post(response_with_body("false\nbad-news"))
156
+
157
+ assert !@controller.verify_recaptcha
158
+ assert_equal 'bad-news', @controller.flash[:recaptcha_error]
159
+ end
160
+
161
+ def test_not_flashing_error_if_request_format_not_in_html
162
+ skip
163
+ @controller.request = stub(:remote_ip => "1.1.1.1", format: :json)
164
+ expect_http_post(response_with_body("false\nbad-news"))
165
+ assert !@controller.verify_recaptcha
166
+ assert_nil @controller.flash[:recaptcha_error]
167
+ end
168
+
169
+ private
170
+
171
+ class TestController
172
+ include Recaptcha::Verify
173
+ attr_accessor :request, :params, :flash
174
+
175
+ def initialize
176
+ @flash = {}
177
+ end
178
+ end
179
+
180
+ def expect_http_post(response, options = {})
181
+ unless options[:exception]
182
+ Net::HTTP.expects(:post_form).with(@expected_uri, @expected_post_data).returns(response)
183
+ else
184
+ Net::HTTP.expects(:post_form).raises response
185
+ end
186
+ end
187
+
188
+ def response_with_body(body)
189
+ stub(:body => body)
190
+ end
191
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cure-recaptcha
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.1
5
+ platform: ruby
6
+ authors:
7
+ - Ward Vandewege
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mocha
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: i18n
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '5.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '5.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: This plugin adds helpers for the reCAPTCHA API
98
+ email:
99
+ - ward@curoverse.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".travis.yml"
106
+ - CHANGELOG
107
+ - Gemfile
108
+ - Gemfile.lock
109
+ - LICENSE
110
+ - README.rdoc
111
+ - Rakefile
112
+ - init.rb
113
+ - lib/recaptcha.rb
114
+ - lib/recaptcha/client_helper.rb
115
+ - lib/recaptcha/configuration.rb
116
+ - lib/recaptcha/merb.rb
117
+ - lib/recaptcha/rails.rb
118
+ - lib/recaptcha/railtie.rb
119
+ - lib/recaptcha/verify.rb
120
+ - lib/recaptcha/version.rb
121
+ - recaptcha.gemspec
122
+ - test/recaptcha_configuration_test.rb
123
+ - test/recaptcha_test.rb
124
+ - test/recaptcha_v1_test.rb
125
+ - test/verify_recaptcha_test.rb
126
+ homepage: http://github.com/cure/recaptcha
127
+ licenses: []
128
+ metadata: {}
129
+ post_install_message:
130
+ rdoc_options: []
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubyforge_project: cure-recaptcha
145
+ rubygems_version: 2.4.8
146
+ signing_key:
147
+ specification_version: 4
148
+ summary: Helpers for the reCAPTCHA API
149
+ test_files: []