recaptcha 0.6.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 15a8d9b4ffc50fb479df2f03065310e3b85be5f4
4
- data.tar.gz: 1d2412b3ce72619d131388e77e9b82a4b1e9de46
3
+ metadata.gz: 19150c1891f5ef4fda5c568d941c8035ef19c0aa
4
+ data.tar.gz: ffac23399306ce2b5c6c5199389cc755abfe2833
5
5
  SHA512:
6
- metadata.gz: f1a53822196216dc231d60369edcce9719e724e4e66a35b57e35b7b57ca8104b2d5211a07231616fad499c13420daa3eb584b5337e87dd47631d40e61d801721
7
- data.tar.gz: e3fef919669e86e48de71216c3def51609e1d525d1fe7cebc5ada112f5f9613d96783625c0d675cddfeafce97d7783006665371db42be17f027248945784ebc6
6
+ metadata.gz: 0734d303c81f727913edef8c3f637b2fbf4d2f4612f170656bf1899b9a2be45fdd06401e63bd8eb9a98dac8eb57f9ffbc139a2d2d17a09f93ed0986cd349d452
7
+ data.tar.gz: cd08fa57ef7c4b3afdc03f8311ab7f4299d0c056686289a7bdff87dd87b6aa6fb5979a7313d0437c3b49ce9730c92000451f429aafe521fc66b5103f5989b8a5
@@ -1,4 +1,19 @@
1
- == 0.3.6 / 2012-01-07
1
+ ## NEXT
2
+ * remove api v1 support
3
+ * remove ssl_api_server_url, nonssl_api_server_url, change api_server_url to always need ssl option
4
+ * removed activesupport dependency for .to_query
5
+ * made flash and models both have descriptive errors
6
+
7
+ ## 0.6.0
8
+ * extract token module
9
+ * need to use `gem "recaptcha", require: "recaptcha/rails"` to get rails helpers installed
10
+
11
+ ## 0.5.0
12
+ * size option
13
+ * support disabling stoken
14
+ * support Rails.env
15
+
16
+ ## 0.3.6 / 2012-01-07
2
17
 
3
18
  * Many documentation changes
4
19
  * Fixed deprecations in dependencies
@@ -6,27 +21,27 @@
6
21
  * Fixes for options hash
7
22
  * Fixes for failing tests
8
23
 
9
- == 0.3.5 / 2012-05-02
24
+ ## 0.3.5 / 2012-05-02
10
25
 
11
26
  * I18n for error messages
12
27
  * Rails: delete flash keys if unused
13
28
 
14
- == 0.3.4 / 2011-12-13
29
+ ## 0.3.4 / 2011-12-13
15
30
 
16
31
  * Rails 3
17
32
  * Remove jeweler
18
33
 
19
- == 0.2.2 / 2009-09-14
34
+ ## 0.2.2 / 2009-09-14
20
35
 
21
36
  * Add a timeout to the validator
22
37
  * Give the documentation some love
23
38
 
24
- == 0.2.1 / 2009-09-14
39
+ ## 0.2.1 / 2009-09-14
25
40
 
26
41
  * Removed Ambethia namespace, and restructured classes a bit
27
42
  * Added an example rails app in the example-rails branch
28
43
 
29
- == 0.2.0 / 2009-09-12
44
+ ## 0.2.0 / 2009-09-12
30
45
 
31
46
  * RecaptchaOptions AJAX API Fix
32
47
  * Added 'cucumber' as a test environment to skip
@@ -35,7 +50,7 @@
35
50
  * Removed dependency on ActiveRecord constant
36
51
  * Add I18n
37
52
 
38
- == 0.1.0 / 2008-2-8
53
+ ## 0.1.0 / 2008-2-8
39
54
 
40
55
  * 1 major enhancement
41
- * Initial Gem Release
56
+ * Initial Gem Release
data/README.md CHANGED
@@ -11,102 +11,56 @@ views you can use the `recaptcha_tags` method to embed the needed javascript,
11
11
  and you can validate in your controllers with `verify_recaptcha` or `verify_recaptcha!`,
12
12
  which throws an error on failiure.
13
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
14
  ## Rails Installation
19
15
 
20
- ```Ruby
21
- gem "recaptcha", require: "recaptcha/rails"
22
- ```
23
-
24
- (Rails < 3.0: install an older release and view it's README)
25
-
26
- ## Setting up your API Keys
27
-
28
- There are multiple ways to setup your reCAPTCHA API key once you
29
- [obtain a pair](https://www.google.com/recaptcha/admin).
30
-
31
- ### Recaptcha.configure
32
-
33
- You may use the block style configuration. The following code could be placed
34
- into a `config/initializers/recaptcha.rb` when used in a Rails project.
35
-
36
- ```Ruby
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 older version of the API,
43
- # only works for versions >= 0.3.7, default value is 'v2':
44
- # config.api_version = 'v1'
45
- end
46
- ```
47
-
48
- This way, you may also set additional options to fit recaptcha into your
49
- deployment environment.
50
-
51
- ### Recaptcha.with_configuration
52
-
53
- If you want to temporarily overwrite the configuration you set with
54
- `Recaptcha.configure` (when testing, for example), you can use a
55
- `Recaptcha#with_configuration` block:
16
+ [obtain a reCAPTCHA API key](https://www.google.com/recaptcha/admin).
56
17
 
57
18
  ```Ruby
58
- Recaptcha.with_configuration(public_key: '12345') do
59
- # Do stuff with the overwritten public_key.
60
- end
19
+ gem "recaptcha", require: "recaptcha/rails"
61
20
  ```
62
21
 
63
- ### Heroku & Shell environment
22
+ Keep keys out of the code base with environment variables.<br/>
23
+ Set in production and locally use [dotenv](https://github.com/bkeepers/dotenv), make sure to add it above recaptcha.
64
24
 
65
- Or, you can keep your keys out of your code base by exporting the following
66
- environment variables. You might do this in the .profile/rc, or equivalent for
67
- the user running your application. This would also be the preffered method
68
- in an Heroku deployment.
25
+ Otherwise see [Alternative API key setup](#alternative-api-key-setup).
69
26
 
70
27
  ```
71
28
  export RECAPTCHA_PUBLIC_KEY = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
72
29
  export RECAPTCHA_PRIVATE_KEY = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
73
30
  ```
74
31
 
75
- ### Per call
76
-
77
- You can also pass in your keys as options at runtime, for example:
32
+ Add `recaptcha_tags` to the forms you want to protect.
78
33
 
79
- ```Ruby
80
- recaptcha_tags public_key: '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
34
+ ```Erb
35
+ <%= form_for @foo do |f| %>
36
+ # ... other tags
37
+ <%= recaptcha_tags %>
38
+ # ... other tags
39
+ <% end %>
81
40
  ```
82
41
 
83
- and later,
42
+ And, add `verify_recaptcha` logic to each form action that you've protected.
84
43
 
85
44
  ```Ruby
86
- verify_recaptcha private_key: '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
45
+ # app/controllers/users_controller.rb
46
+ @user = User.new(params[:user].permit(:name))
47
+ if verify_recaptcha(model: @user) && @user.save
48
+ redirect_to @user
49
+ else
50
+ render 'new'
51
+ end
87
52
  ```
88
53
 
89
- This option might be useful, if the same code base is used for multiple
90
- reCAPTCHA setups.
54
+ ## Sinatra / Rack / Ruby installation
91
55
 
92
- ## To use 'recaptcha'
56
+ See [sinatra demo](/demo/sinatra) for details.
93
57
 
94
- Add `recaptcha_tags` to each form you want to protect.
95
- Place it where you want the recaptcha widget to appear.
58
+ - add `gem 'recaptcha'` to `Gemfile`
59
+ - set env variables
60
+ - `include Recaptcha::ClientHelper` where you need `recaptcha_tags`
61
+ - `include Recaptcha::Verify` where you need `verify_recaptcha`
96
62
 
97
- Example:
98
-
99
- ```Erb
100
- <%= form_for @foo do |f| %>
101
- # ... additional lines truncated for brevity ...
102
- <%= recaptcha_tags %>
103
- # ... additional lines truncated for brevity ...
104
- <% end %>
105
- ```
106
-
107
- And, add `verify_recaptcha` logic to each form action that you've protected.
108
-
109
- ### recaptcha_tags
63
+ ## recaptcha_tags
110
64
 
111
65
  Some of the options available:
112
66
 
@@ -116,16 +70,15 @@ Some of the options available:
116
70
  | :noscript | Include <noscript> content (default `true`)|
117
71
  | :display | Takes a hash containing the `theme` and `tabindex` options per the API. (default `nil`), options: 'red', 'white', 'blackglass', 'clean', 'custom'|
118
72
  | :ajax | Render the dynamic AJAX captcha per the API. (default `false`)|
119
- | :public_key | Your public API key, takes precedence over the ENV variable (default `nil`)|
73
+ | :public_key | Override public API key |
120
74
  | :error | Override the error code returned from the reCAPTCHA API (default `nil`)|
121
75
  | :stoken | Include in reCAPTCHA API v2 the security token (default `true`)|
122
76
  | :size | Specify a size (default `nil`)|
123
77
 
124
-
125
78
  You can also override the html attributes for the sizes of the generated `textarea` and `iframe`
126
79
  elements, if CSS isn't your thing. Inspect the source of `recaptcha_tags` to see these options.
127
80
 
128
- ### verify_recaptcha
81
+ ## verify_recaptcha
129
82
 
130
83
  This method returns `true` or `false` after processing the parameters from the reCAPTCHA widget. Why
131
84
  isn't this a model validation? Because that violates MVC. You can use it like this, or how ever you
@@ -139,135 +92,10 @@ Some of the options available:
139
92
  | :model | Model to set errors
140
93
  | :attribute | Model attribute to receive errors (default :base)
141
94
  | :message | Custom error message
142
- | :private_key | Your private API key, takes precedence over the ENV variable (default `nil`).
95
+ | :private_key | Override private API key.
143
96
  | :timeout | The number of seconds to wait for reCAPTCHA servers before give up. (default `3`)
97
+ | :response | Custom response parameter (default: params['g-recaptcha-response'])
144
98
 
145
- ```Ruby
146
- respond_to do |format|
147
- if verify_recaptcha(model @post, message: "Oh! It's error with reCAPTCHA!") && @post.save
148
- # ...
149
- else
150
- # ...
151
- end
152
- end
153
- ```
154
-
155
- ### Add multiple widgets to the same page
156
-
157
- This is an example taken from the [official google documentation](https://developers.google.com/recaptcha/docs/display).
158
-
159
- Add a script tag for a callback
160
-
161
- ```Html
162
- <script type="text/javascript">
163
- var verifyCallback = function(response) {
164
- alert(response);
165
- };
166
- var widgetId1;
167
- var widgetId2;
168
- var onloadCallback = function() {
169
- // Renders the HTML element with id 'example1' as a reCAPTCHA widget.
170
- // The id of the reCAPTCHA widget is assigned to 'widgetId1'.
171
- widgetId1 = grecaptcha.render('example1', {
172
- 'sitekey' : "<%= Recaptcha.configuration.public_key %>",
173
- 'theme' : 'light'
174
- });
175
- widgetId2 = grecaptcha.render(document.getElementById('example2'), {
176
- 'sitekey' : "<%= Recaptcha.configuration.public_key %>"
177
- });
178
- grecaptcha.render('example3', {
179
- 'sitekey' : "<%= Recaptcha.configuration.public_key %>",
180
- 'callback' : verifyCallback,
181
- 'theme' : 'dark'
182
- });
183
- };
184
- </script>
185
- ```
186
-
187
- In the callback you will have the `sitekey` generated by this gem with `<%= Recaptcha.configuration.public_key %>`
188
-
189
- Next you need to have some elements with an id matching those specified in the callback
190
-
191
- ```Erb
192
- <%= form_for @foo do |f| %>
193
- # ... additional lines truncated for brevity ...
194
- <div id="example1"></div>
195
- # ... additional lines truncated for brevity ...
196
- <% end %>
197
- <%= form_for @foo2 do |f| %>
198
- # ... additional lines truncated for brevity ...
199
- <div id="example2"></div>
200
- # ... additional lines truncated for brevity ...
201
- <% end %>
202
- <%= form_for @foo3 do |f| %>
203
- # ... additional lines truncated for brevity ...
204
- <div id="example3"></div>
205
- # ... additional lines truncated for brevity ...
206
- <% end %>
207
- ```
208
-
209
- And finally you need a script tag that gets the reCAPTCHA code from google and tells it that your code is explicit and gives it the callback.
210
-
211
- ```Html
212
- <script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
213
- ```
214
-
215
- Now all together:
216
-
217
- ```Html
218
- <html>
219
- <head>
220
- <title>reCAPTCHA demo: Explicit render for multiple widgets</title>
221
- <script type="text/javascript">
222
- var verifyCallback = function(response) {
223
- alert(response);
224
- };
225
- var widgetId1;
226
- var widgetId2;
227
- var onloadCallback = function() {
228
- // Renders the HTML element with id 'example1' as a reCAPTCHA widget.
229
- // The id of the reCAPTCHA widget is assigned to 'widgetId1'.
230
- widgetId1 = grecaptcha.render('example1', {
231
- 'sitekey' : "<%= Recaptcha.configuration.public_key %>",
232
- 'theme' : 'light'
233
- });
234
- widgetId2 = grecaptcha.render(document.getElementById('example2'), {
235
- 'sitekey' : "<%= Recaptcha.configuration.public_key %>"
236
- });
237
- grecaptcha.render('example3', {
238
- 'sitekey' : "<%= Recaptcha.configuration.public_key %>",
239
- 'callback' : verifyCallback,
240
- 'theme' : 'dark'
241
- });
242
- };
243
- </script>
244
- </head>
245
- <body>
246
- <%= form_for @foo do |f| %>
247
- # ... additional lines truncated for brevity ...
248
- <div id="example1"></div>
249
- # ... additional lines truncated for brevity ...
250
- <% end %>
251
- <%= form_for @foo2 do |f| %>
252
- # ... additional lines truncated for brevity ...
253
- <div id="example2"></div>
254
- # ... additional lines truncated for brevity ...
255
- <% end %>
256
- <%= form_for @foo3 do |f| %>
257
- # ... additional lines truncated for brevity ...
258
- <div id="example3"></div>
259
- # ... additional lines truncated for brevity ...
260
- <% end %>
261
- <script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
262
- </body>
263
- </html>
264
- ```
265
-
266
- The only real difference between this example and the google example is you will use the `<%= Recaptcha.configuration.public_key %>` for the `sitekey`
267
-
268
- If your callback has to live on another file (maybe a layout), then you would set the callback on window `window.onloadCallback = function() {...}`
269
-
270
- Then on the backend, you will still use the `verify_recaptcha` as explained in this readme.
271
99
 
272
100
  ## I18n support
273
101
  reCAPTCHA passes two types of error explanation to a linked model. It will use the I18n gem
@@ -287,9 +115,49 @@ en:
287
115
  ```
288
116
 
289
117
  ## Testing
290
- By default, reCAPTCHA is skipped on "test" env, so if you need to make sure it's working properly, just remove the "test" entry of the skip_environment inside Recapcha class, look:
291
118
 
119
+ By default, reCAPTCHA is skipped in "test" and "cucumber" env. To enable it during test:
292
120
 
293
121
  ```Ruby
294
122
  Recaptcha.configuration.skip_verify_env.delete("test")
295
123
  ```
124
+
125
+ ## Alternative API key setup
126
+
127
+ ### Recaptcha.configure
128
+
129
+ ```Ruby
130
+ # config/initializers/recaptcha.rb
131
+ Recaptcha.configure do |config|
132
+ config.public_key = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
133
+ config.private_key = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
134
+ # Uncomment the following line if you are using a proxy server:
135
+ # config.proxy = 'http://myproxy.com.au:8080'
136
+ end
137
+ ```
138
+
139
+ ### Recaptcha.with_configuration
140
+
141
+ For temporary overwrites (not thread safe).
142
+
143
+ ```Ruby
144
+ Recaptcha.with_configuration(public_key: '12345') do
145
+ # Do stuff with the overwritten public_key.
146
+ end
147
+ ```
148
+
149
+ ### Per call
150
+
151
+ Pass in keys as options at runtime, for code base with multiple reCAPTCHA setups:
152
+
153
+ ```Ruby
154
+ recaptcha_tags public_key: '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
155
+
156
+ and
157
+
158
+ verify_recaptcha private_key: '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
159
+ ```
160
+
161
+ ## Misc
162
+ - Check out the [wiki](https://github.com/ambethia/recaptcha/wiki) and leave whatever you found valuable there.
163
+ - [Add multiple widgets to the same page](https://github.com/ambethia/recaptcha/wiki/Add-multiple-widgets-to-the-same-page)
@@ -2,27 +2,19 @@ require 'recaptcha/configuration'
2
2
  require 'recaptcha/client_helper'
3
3
  require 'recaptcha/verify'
4
4
  require 'recaptcha/token'
5
+ require 'uri'
5
6
 
6
7
  module Recaptcha
7
- CONFIG =
8
- {
9
- 'v1' => {
10
- 'server_url' => '//www.google.com/recaptcha/api',
11
- 'secure_server_url' => 'https://www.google.com/recaptcha/api',
12
- 'verify_url' => 'http://www.google.com/recaptcha/api/verify'
13
- },
14
-
15
- 'v2' => {
16
- 'server_url' => '//www.google.com/recaptcha/api.js',
17
- 'secure_server_url' => 'https://www.google.com/recaptcha/api.js',
18
- 'verify_url' => 'https://www.google.com/recaptcha/api/siteverify'
19
- }
20
- }
21
-
22
- RECAPTCHA_API_VERSION = 'v2'
8
+ CONFIG = {
9
+ 'server_url' => '//www.google.com/recaptcha/api.js',
10
+ 'secure_server_url' => 'https://www.google.com/recaptcha/api.js',
11
+ 'verify_url' => 'https://www.google.com/recaptcha/api/siteverify'
12
+ }
13
+
23
14
  USE_SSL_BY_DEFAULT = false
24
15
  HANDLE_TIMEOUTS_GRACEFULLY = true
25
16
  SKIP_VERIFY_ENV = ['test', 'cucumber']
17
+ DEFAULT_TIMEOUT = 3
26
18
 
27
19
  # Gives access to the current Configuration.
28
20
  def self.configuration
@@ -54,6 +46,34 @@ module Recaptcha
54
46
  result
55
47
  end
56
48
 
49
+ def self.get(verify_hash, options)
50
+ http = if Recaptcha.configuration.proxy
51
+ proxy_server = URI.parse(Recaptcha.configuration.proxy)
52
+ Net::HTTP::Proxy(proxy_server.host, proxy_server.port, proxy_server.user, proxy_server.password)
53
+ else
54
+ Net::HTTP
55
+ end
56
+ query = URI.encode_www_form(verify_hash)
57
+ uri = URI.parse(Recaptcha.configuration.verify_url + '?' + query)
58
+ http_instance = http.new(uri.host, uri.port)
59
+ http_instance.read_timeout = http_instance.open_timeout = options[:timeout] || DEFAULT_TIMEOUT
60
+ if uri.port == 443
61
+ http_instance.use_ssl = true
62
+ http_instance.verify_mode = OpenSSL::SSL::VERIFY_NONE
63
+ end
64
+ request = Net::HTTP::Get.new(uri.request_uri)
65
+ http_instance.request(request).body
66
+ end
67
+
68
+ def self.i18n(key, default)
69
+ if defined?(I18n)
70
+ I18n.translate(key, default: default)
71
+ else
72
+ default
73
+ end
74
+ end
75
+
76
+
57
77
  class RecaptchaError < StandardError
58
78
  end
59
79
 
@@ -3,129 +3,50 @@ module Recaptcha
3
3
  # Your public API can be specified in the +options+ hash or preferably
4
4
  # using the Configuration.
5
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
6
+ public_key = options[:public_key] || Recaptcha.configuration.public_key!
9
7
 
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
- public_key = options[:public_key] ||= Recaptcha.configuration.public_key
67
- raise RecaptchaError, "No public key specified." unless public_key
68
- private_key = options[:private_key] ||= Recaptcha.configuration.private_key
69
- raise RecaptchaError, "No private key specified." unless private_key
70
- error = options[:error] ||= ((defined? flash) ? flash[:recaptcha_error] : "") # TODO not being used !?
71
- uri = Recaptcha.configuration.api_server_url(options[:ssl])
72
- uri += "?hl=#{options[:hl]}" unless options[:hl].blank?
73
-
74
- html = ""
75
- html << %{<script src="#{uri}" async defer></script>\n}
76
-
77
- data_attributes = options.slice(:theme, :type, :callback, :expired_callback, :size)
78
- data_attributes[:sitekey] = public_key
8
+ script_url = Recaptcha.configuration.api_server_url(ssl: options[:ssl])
9
+ script_url += "?hl=#{options[:hl]}" unless options[:hl].to_s == ""
10
+ fallback_uri = "#{script_url.chomp('.js')}/fallback?k=#{public_key}"
79
11
 
80
- if options[:stoken] != false
81
- data_attributes[:stoken] = Recaptcha::Token.secure_token
12
+ data_attributes = [:theme, :type, :callback, :expired_callback, :size]
13
+ data_attributes = options.each_with_object({}) do |(k, v), a|
14
+ a[k] = v if data_attributes.include?(k)
82
15
  end
16
+ data_attributes[:sitekey] = public_key
17
+ data_attributes[:stoken] = Recaptcha::Token.secure_token if options[:stoken] != false
18
+ data_attributes = data_attributes.map { |k,v| %{data-#{k.to_s.tr('_','-')}="#{v}"} }.join(" ")
83
19
 
84
- data_attributes = data_attributes.map {|k,v| %{data-#{k.to_s.gsub(/_/,'-')}="#{v}"} }.join(" ")
85
-
20
+ html = %{<script src="#{script_url}" async defer></script>\n}
86
21
  html << %{<div class="g-recaptcha" #{data_attributes}></div>\n}
87
22
 
88
- unless options[:noscript] == false
89
- fallback_uri = "#{uri.chomp('.js')}/fallback?k=#{public_key}"
90
- html << %{<noscript>}
91
- html << %{<div style="width: 302px; height: 352px;">}
92
- html << %{ <div style="width: 302px; height: 352px; position: relative;">}
93
- html << %{ <div style="width: 302px; height: 352px; position: absolute;">}
94
- html << %{ <iframe src="#{fallback_uri}"}
95
- html << %{ frameborder="0" scrolling="no"}
96
- html << %{ style="width: 302px; height:352px; border-style: none;">}
97
- html << %{ </iframe>}
98
- html << %{ </div>}
99
- html << %{ <div style="width: 250px; height: 80px; position: absolute; border-style: none; }
100
- html << %{ bottom: 21px; left: 25px; margin: 0px; padding: 0px; right: 25px;">}
101
- html << %{ <textarea id="g-recaptcha-response" name="g-recaptcha-response" }
102
- html << %{ class="g-recaptcha-response" }
103
- html << %{ style="width: 250px; height: 80px; border: 1px solid #c1c1c1; }
104
- html << %{ margin: 0px; padding: 0px; resize: none;" value=""> }
105
- html << %{ </textarea>}
106
- html << %{ </div>}
107
- html << %{ </div>}
108
- html << %{ </div>}
109
- html << %{</noscript>}
23
+ if options[:noscript] != false
24
+ html << <<-HTML
25
+ <noscript>
26
+ <div style="width: 302px; height: 352px;">
27
+ <div style="width: 302px; height: 352px; position: relative;">
28
+ <div style="width: 302px; height: 352px; position: absolute;">
29
+ <iframe
30
+ src="#{fallback_uri}"
31
+ frameborder="0" scrolling="no"
32
+ style="width: 302px; height:352px; border-style: none;">
33
+ </iframe>
34
+ </div>
35
+ <div style="width: 250px; height: 80px; position: absolute; border-style: none;
36
+ bottom: 21px; left: 25px; margin: 0px; padding: 0px; right: 25px;">
37
+ <textarea id="g-recaptcha-response" name="g-recaptcha-response"
38
+ class="g-recaptcha-response"
39
+ style="width: 250px; height: 80px; border: 1px solid #c1c1c1;
40
+ margin: 0px; padding: 0px; resize: none;" value="">
41
+ </textarea>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ </noscript>
46
+ HTML
110
47
  end
111
48
 
112
- (html.respond_to?(:html_safe) && html.html_safe) || html
113
- end
114
-
115
- private
116
-
117
- def hash_to_json(hash)
118
- result = "{"
119
- result << hash.map do |k, v|
120
- if v.is_a?(Hash)
121
- "\"#{k}\": #{hash_to_json(v)}"
122
- elsif ! v.is_a?(String) || k.to_s =~ %r{(callback|expired-callback)}
123
- "\"#{k}\": #{v}"
124
- else
125
- "\"#{k}\": \"#{v}\""
126
- end
127
- end.join(", ")
128
- result << "}"
49
+ html.respond_to?(:html_safe) ? html.html_safe : html
129
50
  end
130
51
  end
131
52
  end
@@ -28,47 +28,33 @@ module Recaptcha
28
28
  # end
29
29
  #
30
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
31
+ attr_accessor :skip_verify_env, :private_key, :public_key, :proxy, :handle_timeouts_gracefully, :use_ssl_by_default
38
32
 
39
33
  def initialize #:nodoc:
40
- @api_version = RECAPTCHA_API_VERSION
41
34
  @skip_verify_env = SKIP_VERIFY_ENV
42
35
  @handle_timeouts_gracefully = HANDLE_TIMEOUTS_GRACEFULLY
43
36
  @use_ssl_by_default = USE_SSL_BY_DEFAULT
44
37
 
45
38
  @private_key = ENV['RECAPTCHA_PRIVATE_KEY']
46
- @public_key = ENV['RECAPTCHA_PUBLIC_KEY']
39
+ @public_key = ENV['RECAPTCHA_PUBLIC_KEY']
47
40
  end
48
41
 
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
42
+ def private_key!
43
+ private_key || raise(RecaptchaError, "No private key specified.")
52
44
  end
53
45
 
54
- def nonssl_api_server_url
55
- CONFIG[@api_version]['server_url']
46
+ def public_key!
47
+ public_key || raise(RecaptchaError, "No public key specified.")
56
48
  end
57
49
 
58
- def ssl_api_server_url
59
- CONFIG[@api_version]['secure_server_url']
50
+ def api_server_url(ssl: nil)
51
+ ssl = use_ssl_by_default if ssl.nil?
52
+ key = (ssl ? 'secure_server_url' : 'server_url')
53
+ CONFIG.fetch(key)
60
54
  end
61
55
 
62
56
  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'
57
+ CONFIG.fetch('verify_url')
72
58
  end
73
59
  end
74
60
  end
@@ -1,101 +1,53 @@
1
- require "uri"
2
- require "json"
1
+ require 'json'
3
2
 
4
3
  module Recaptcha
5
4
  module Verify
6
- DEFAULT_TIMEOUT = 3
7
-
8
5
  # Your private API can be specified in the +options+ hash or preferably
9
6
  # using the Configuration.
10
7
  def verify_recaptcha(options = {})
11
8
  options = {:model => options} unless options.is_a? Hash
12
-
13
- env_options = options[:env] || ENV['RAILS_ENV'] || (Rails.env if defined? Rails.env)
14
- return true if Recaptcha.configuration.skip_verify_env.include? env_options
15
9
  model = options[:model]
16
10
  attribute = options[:attribute] || :base
17
- private_key = options[:private_key] || Recaptcha.configuration.private_key
18
- raise RecaptchaError, "No private key specified." unless private_key
19
11
 
20
- begin
21
- recaptcha = nil
22
- if Recaptcha.configuration.proxy
23
- proxy_server = URI.parse(Recaptcha.configuration.proxy)
24
- http = Net::HTTP::Proxy(proxy_server.host, proxy_server.port, proxy_server.user, proxy_server.password)
25
- else
26
- http = Net::HTTP
27
- end
12
+ return true if Recaptcha::Verify.skip?(options[:env])
13
+
14
+ private_key = options[:private_key] || Recaptcha.configuration.private_key!
15
+ recaptcha_response = options[:response] || params['g-recaptcha-response'].to_s
28
16
 
17
+ begin
29
18
  # env['REMOTE_ADDR'] to retrieve IP for Grape API
30
19
  remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR'])
31
- if Recaptcha.configuration.v1?
32
- verify_hash = {
33
- "privatekey" => private_key,
34
- "remoteip" => remote_ip,
35
- "challenge" => params[:recaptcha_challenge_field],
36
- "response" => params[:recaptcha_response_field]
37
- }
38
- Timeout::timeout(options[:timeout] || DEFAULT_TIMEOUT) do
39
- recaptcha = http.post_form(URI.parse(Recaptcha.configuration.verify_url), verify_hash)
40
- end
41
- answer, error = recaptcha.body.split.map { |s| s.chomp }
42
- end
20
+ verify_hash = {
21
+ "secret" => private_key,
22
+ "remoteip" => remote_ip.to_s,
23
+ "response" => recaptcha_response
24
+ }
43
25
 
44
- if Recaptcha.configuration.v2?
45
- verify_hash = {
46
- "secret" => private_key,
47
- "remoteip" => remote_ip,
48
- "response" => params['g-recaptcha-response']
49
- }
50
-
51
- Timeout::timeout(options[:timeout] || DEFAULT_TIMEOUT) do
52
- uri = URI.parse(Recaptcha.configuration.verify_url + '?' + verify_hash.to_query)
53
- http_instance = http.new(uri.host, uri.port)
54
- if uri.port == 443
55
- http_instance.use_ssl =
56
- http_instance.verify_mode = OpenSSL::SSL::VERIFY_NONE
57
- end
58
- request = Net::HTTP::Get.new(uri.request_uri)
59
- recaptcha = http_instance.request(request)
60
- end
61
- answer, error = JSON.parse(recaptcha.body).values
62
- end
26
+ reply = Recaptcha.get(verify_hash, options)
27
+ answer = JSON.parse(reply)['success']
63
28
 
64
29
  if answer.to_s == 'true'
65
- flash.delete(:recaptcha_error) if request_in_html_format?
30
+ flash.delete(:recaptcha_error) if recaptcha_flash_supported?
66
31
  true
67
32
  else
68
- error = 'verification_failed' if error && Recaptcha.configuration.v2?
69
- if request_in_html_format?
70
- flash[:recaptcha_error] = if defined?(I18n)
71
- I18n.translate("recaptcha.errors.#{error}", default: error)
72
- else
73
- error
74
- end
75
- end
76
-
77
- if model
78
- message = "Word verification response is incorrect, please try again."
79
- message = I18n.translate('recaptcha.errors.verification_failed', default: message) if defined?(I18n)
80
- model.errors.add attribute, options[:message] || message
81
- end
33
+ recaptcha_error(
34
+ model,
35
+ attribute,
36
+ options[:message],
37
+ "recaptcha.errors.verification_failed",
38
+ "Word verification response is incorrect, please try again."
39
+ )
82
40
  false
83
41
  end
84
42
  rescue Timeout::Error
85
43
  if Recaptcha.configuration.handle_timeouts_gracefully
86
- if request_in_html_format?
87
- flash[:recaptcha_error] = if defined?(I18n)
88
- I18n.translate('recaptcha.errors.recaptcha_unreachable', default: 'Recaptcha unreachable.')
89
- else
90
- 'Recaptcha unreachable.'
91
- end
92
- end
93
-
94
- if model
95
- message = "Oops, we failed to validate your word verification response. Please try again."
96
- message = I18n.translate('recaptcha.errors.recaptcha_unreachable', default: message) if defined?(I18n)
97
- model.errors.add attribute, options[:message] || message
98
- end
44
+ recaptcha_error(
45
+ model,
46
+ attribute,
47
+ options[:message],
48
+ "recaptcha.errors.recaptcha_unreachable",
49
+ "Oops, we failed to validate your word verification response. Please try again."
50
+ )
99
51
  false
100
52
  else
101
53
  raise RecaptchaError, "Recaptcha unreachable."
@@ -105,12 +57,25 @@ module Recaptcha
105
57
  end
106
58
  end
107
59
 
108
- def request_in_html_format?
60
+ def verify_recaptcha!(options = {})
61
+ verify_recaptcha(options) or raise VerifyError
62
+ end
63
+
64
+ private
65
+
66
+ def recaptcha_error(model, attribute, message, key, default)
67
+ message = message || Recaptcha.i18n(key, default)
68
+ flash[:recaptcha_error] = message if recaptcha_flash_supported?
69
+ model.errors.add attribute, message if model
70
+ end
71
+
72
+ def recaptcha_flash_supported?
109
73
  request.respond_to?(:format) && request.format == :html && respond_to?(:flash)
110
74
  end
111
75
 
112
- def verify_recaptcha!(options = {})
113
- verify_recaptcha(options) or raise VerifyError
76
+ def self.skip?(env)
77
+ env ||= ENV['RAILS_ENV'] || (Rails.env if defined? Rails.env)
78
+ Recaptcha.configuration.skip_verify_env.include? env
114
79
  end
115
80
  end
116
81
  end
@@ -1,3 +1,3 @@
1
1
  module Recaptcha
2
- VERSION = "0.6.0"
2
+ VERSION = "1.0.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recaptcha
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason L Perry
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-19 00:00:00.000000000 Z
11
+ date: 2015-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: webmock
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  description: Helpers for the reCAPTCHA API
126
140
  email:
127
141
  - jasper@ambethia.com
@@ -129,7 +143,7 @@ executables: []
129
143
  extensions: []
130
144
  extra_rdoc_files: []
131
145
  files:
132
- - CHANGELOG
146
+ - CHANGELOG.md
133
147
  - LICENSE
134
148
  - README.md
135
149
  - lib/recaptcha.rb