recaptcha 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +295 -0
- data/lib/recaptcha.rb +1 -6
- data/lib/recaptcha/client_helper.rb +31 -12
- data/lib/recaptcha/rails.rb +10 -2
- data/lib/recaptcha/verify.rb +31 -26
- data/lib/recaptcha/version.rb +1 -1
- metadata +43 -31
- data/.gitignore +0 -8
- data/.travis.yml +0 -3
- data/Gemfile +0 -3
- data/Gemfile.lock +0 -52
- data/README.rdoc +0 -151
- data/Rakefile +0 -8
- data/init.rb +0 -5
- data/lib/recaptcha/merb.rb +0 -4
- data/lib/recaptcha/railtie.rb +0 -15
- data/recaptcha.gemspec +0 -26
- data/test/recaptcha_configuration_test.rb +0 -44
- data/test/recaptcha_test.rb +0 -54
- data/test/recaptcha_v1_test.rb +0 -35
- data/test/verify_recaptcha_test.rb +0 -191
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d8c84c84605f3b19d067af5b08d173f5dd681f2
|
4
|
+
data.tar.gz: c0126d1350d3da2dda33a8d4a2932a0b1ad5f504
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ee980f5953e85425572add41e07b142b323743f8f0c14824145604a8f20176b6a54b5d365852f4dbadd283ecc3e67bf203599e8f03c4c9afc5a5d58c541c5a4
|
7
|
+
data.tar.gz: 8a8677420abff0ceac5f2674fd58da71623b980ff3336c6a2aaf196562adce8d295257d73c964cf220ed98ea1119f4723ea794c7acd7c4b004ff83edcda1fa10
|
data/README.md
ADDED
@@ -0,0 +1,295 @@
|
|
1
|
+
# reCAPTCHA
|
2
|
+
|
3
|
+
Author: Jason L Perry (http://ambethia.com)<br/>
|
4
|
+
Copyright: Copyright (c) 2007-2013 Jason L Perry<br/>
|
5
|
+
License: [MIT](http://creativecommons.org/licenses/MIT/)<br/>
|
6
|
+
Info: https://github.com/ambethia/recaptcha<br/>
|
7
|
+
Bugs: https://github.com/ambethia/recaptcha/issues<br/>
|
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
|
+
```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:
|
56
|
+
|
57
|
+
```Ruby
|
58
|
+
Recaptcha.with_configuration(public_key: '12345') do
|
59
|
+
# Do stuff with the overwritten public_key.
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
### Heroku & Shell environment
|
64
|
+
|
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.
|
69
|
+
|
70
|
+
```
|
71
|
+
export RECAPTCHA_PUBLIC_KEY = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
|
72
|
+
export RECAPTCHA_PRIVATE_KEY = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
|
73
|
+
```
|
74
|
+
|
75
|
+
### Per call
|
76
|
+
|
77
|
+
You can also pass in your keys as options at runtime, for example:
|
78
|
+
|
79
|
+
```Ruby
|
80
|
+
recaptcha_tags public_key: '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy'
|
81
|
+
```
|
82
|
+
|
83
|
+
and later,
|
84
|
+
|
85
|
+
```Ruby
|
86
|
+
verify_recaptcha private_key: '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx'
|
87
|
+
```
|
88
|
+
|
89
|
+
This option might be useful, if the same code base is used for multiple
|
90
|
+
reCAPTCHA setups.
|
91
|
+
|
92
|
+
## To use 'recaptcha'
|
93
|
+
|
94
|
+
Add `recaptcha_tags` to each form you want to protect.
|
95
|
+
Place it where you want the recaptcha widget to appear.
|
96
|
+
|
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
|
110
|
+
|
111
|
+
Some of the options available:
|
112
|
+
|
113
|
+
| Option | Description |
|
114
|
+
|-------------|-------------|
|
115
|
+
| :ssl | Uses secure http for captcha widget (default `false`, but can be changed by setting `config.use_ssl_by_default`)|
|
116
|
+
| :noscript | Include <noscript> content (default `true`)|
|
117
|
+
| :display | Takes a hash containing the `theme` and `tabindex` options per the API. (default `nil`), options: 'red', 'white', 'blackglass', 'clean', 'custom'|
|
118
|
+
| :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`)|
|
120
|
+
| :error | Override the error code returned from the reCAPTCHA API (default `nil`)|
|
121
|
+
| :stoken | Include in reCAPTCHA API v2 the security token (default `true`)|
|
122
|
+
| :size | Specify a size (default `nil`)|
|
123
|
+
|
124
|
+
|
125
|
+
You can also override the html attributes for the sizes of the generated `textarea` and `iframe`
|
126
|
+
elements, if CSS isn't your thing. Inspect the source of `recaptcha_tags` to see these options.
|
127
|
+
|
128
|
+
### verify_recaptcha
|
129
|
+
|
130
|
+
This method returns `true` or `false` after processing the parameters from the reCAPTCHA widget. Why
|
131
|
+
isn't this a model validation? Because that violates MVC. You can use it like this, or how ever you
|
132
|
+
like. Passing in the ActiveRecord object is optional, if you do--and the captcha fails to verify--an
|
133
|
+
error will be added to the object for you to use.
|
134
|
+
|
135
|
+
Some of the options available:
|
136
|
+
|
137
|
+
| Option | Description |
|
138
|
+
|--------------|-------------|
|
139
|
+
| :model | Model to set errors
|
140
|
+
| :attribute | Model attribute to receive errors (default :base)
|
141
|
+
| :message | Custom error message
|
142
|
+
| :private_key | Your private API key, takes precedence over the ENV variable (default `nil`).
|
143
|
+
| :timeout | The number of seconds to wait for reCAPTCHA servers before give up. (default `3`)
|
144
|
+
|
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
|
+
|
272
|
+
## I18n support
|
273
|
+
reCAPTCHA passes two types of error explanation to a linked model. It will use the I18n gem
|
274
|
+
to translate the default error message if I18n is available. To customize the messages to your locale,
|
275
|
+
add these keys to your I18n backend:
|
276
|
+
|
277
|
+
`recaptcha.errors.verification_failed` error message displayed if the captcha words didn't match
|
278
|
+
`recaptcha.errors.recaptcha_unreachable` displayed if a timeout error occured while attempting to verify the captcha
|
279
|
+
|
280
|
+
Also you can translate API response errors to human friendly by adding translations to the locale (`config/locales/en.yml`):
|
281
|
+
|
282
|
+
```Yaml
|
283
|
+
en:
|
284
|
+
recaptcha:
|
285
|
+
errors:
|
286
|
+
incorrect-captcha-sol: 'Fail'
|
287
|
+
```
|
288
|
+
|
289
|
+
## 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
|
+
|
292
|
+
|
293
|
+
```Ruby
|
294
|
+
Recaptcha.configuration.skip_verify_env.delete("test")
|
295
|
+
```
|
data/lib/recaptcha.rb
CHANGED
@@ -18,7 +18,7 @@ module Recaptcha
|
|
18
18
|
}
|
19
19
|
}
|
20
20
|
|
21
|
-
RECAPTCHA_API_VERSION = 'v2'
|
21
|
+
RECAPTCHA_API_VERSION = 'v2'
|
22
22
|
USE_SSL_BY_DEFAULT = false
|
23
23
|
HANDLE_TIMEOUTS_GRACEFULLY = true
|
24
24
|
SKIP_VERIFY_ENV = ['test', 'cucumber']
|
@@ -58,9 +58,4 @@ module Recaptcha
|
|
58
58
|
|
59
59
|
class VerifyError < RecaptchaError
|
60
60
|
end
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
if defined?(Rails)
|
65
|
-
require 'recaptcha/rails'
|
66
61
|
end
|
@@ -63,20 +63,39 @@ module Recaptcha
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def v2_tags(options)
|
66
|
-
|
67
|
-
raise RecaptchaError, "No public key specified." unless
|
68
|
-
|
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 !?
|
69
71
|
uri = Recaptcha.configuration.api_server_url(options[:ssl])
|
70
72
|
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
73
|
|
74
74
|
html = ""
|
75
75
|
html << %{<script src="#{uri}" async defer></script>\n}
|
76
|
-
|
77
|
-
|
76
|
+
|
77
|
+
data_attributes = options.slice(:theme, :type, :callback, :expired_callback, :size)
|
78
|
+
data_attributes[:sitekey] = public_key
|
79
|
+
|
80
|
+
if options[:stoken] != false
|
81
|
+
stoken_json = hash_to_json({'session_id' => SecureRandom.uuid, 'ts_ms' => (Time.now.to_f * 1000).to_i})
|
82
|
+
cipher = OpenSSL::Cipher::AES128.new(:ECB)
|
83
|
+
private_key_digest = Digest::SHA1.digest(private_key)[0...16]
|
84
|
+
|
85
|
+
cipher.encrypt
|
86
|
+
cipher.key = private_key_digest
|
87
|
+
encrypted_stoken = cipher.update(stoken_json) << cipher.final
|
88
|
+
encoded_stoken = Base64.urlsafe_encode64(encrypted_stoken).gsub(/\=+\Z/, '')
|
89
|
+
|
90
|
+
data_attributes[:stoken] = encoded_stoken
|
91
|
+
end
|
92
|
+
|
93
|
+
data_attributes = data_attributes.map {|k,v| %{data-#{k.to_s.gsub(/_/,'-')}="#{v}"} }.join(" ")
|
94
|
+
|
95
|
+
html << %{<div class="g-recaptcha" #{data_attributes}></div>\n}
|
96
|
+
|
78
97
|
unless options[:noscript] == false
|
79
|
-
fallback_uri = "#{uri.chomp('.js')}/fallback?k=#{
|
98
|
+
fallback_uri = "#{uri.chomp('.js')}/fallback?k=#{public_key}"
|
80
99
|
html << %{<noscript>}
|
81
100
|
html << %{<div style="width: 302px; height: 352px;">}
|
82
101
|
html << %{ <div style="width: 302px; height: 352px; position: relative;">}
|
@@ -99,7 +118,7 @@ module Recaptcha
|
|
99
118
|
html << %{</noscript>}
|
100
119
|
end
|
101
120
|
|
102
|
-
|
121
|
+
(html.respond_to?(:html_safe) && html.html_safe) || html
|
103
122
|
end
|
104
123
|
|
105
124
|
private
|
@@ -109,7 +128,7 @@ module Recaptcha
|
|
109
128
|
result << hash.map do |k, v|
|
110
129
|
if v.is_a?(Hash)
|
111
130
|
"\"#{k}\": #{hash_to_json(v)}"
|
112
|
-
elsif ! v.is_a?(String) || k.to_s
|
131
|
+
elsif ! v.is_a?(String) || k.to_s =~ %r{(callback|expired-callback)}
|
113
132
|
"\"#{k}\": #{v}"
|
114
133
|
else
|
115
134
|
"\"#{k}\": \"#{v}\""
|
@@ -117,5 +136,5 @@ module Recaptcha
|
|
117
136
|
end.join(", ")
|
118
137
|
result << "}"
|
119
138
|
end
|
120
|
-
end
|
121
|
-
end
|
139
|
+
end
|
140
|
+
end
|
data/lib/recaptcha/rails.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
require 'recaptcha'
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
module Rails
|
5
|
+
module Recaptcha
|
6
|
+
class Railtie < Rails::Railtie
|
7
|
+
initializer :recaptcha do
|
8
|
+
ActionView::Base.send(:include, ::Recaptcha::ClientHelper)
|
9
|
+
ActionController::Base.send(:include, ::Recaptcha::Verify)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/recaptcha/verify.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
require "uri"
|
2
|
+
require "json"
|
3
|
+
|
2
4
|
module Recaptcha
|
3
5
|
module Verify
|
6
|
+
DEFAULT_TIMEOUT = 3
|
7
|
+
|
4
8
|
# Your private API can be specified in the +options+ hash or preferably
|
5
9
|
# using the Configuration.
|
6
10
|
def verify_recaptcha(options = {})
|
7
11
|
options = {:model => options} unless options.is_a? Hash
|
8
12
|
|
9
|
-
env_options = options[:env] || ENV['RAILS_ENV']
|
13
|
+
env_options = options[:env] || ENV['RAILS_ENV'] || (Rails.env if defined? Rails.env)
|
10
14
|
return true if Recaptcha.configuration.skip_verify_env.include? env_options
|
11
15
|
model = options[:model]
|
12
16
|
attribute = options[:attribute] || :base
|
@@ -15,7 +19,7 @@ module Recaptcha
|
|
15
19
|
|
16
20
|
begin
|
17
21
|
recaptcha = nil
|
18
|
-
if
|
22
|
+
if Recaptcha.configuration.proxy
|
19
23
|
proxy_server = URI.parse(Recaptcha.configuration.proxy)
|
20
24
|
http = Net::HTTP::Proxy(proxy_server.host, proxy_server.port, proxy_server.user, proxy_server.password)
|
21
25
|
else
|
@@ -31,7 +35,7 @@ module Recaptcha
|
|
31
35
|
"challenge" => params[:recaptcha_challenge_field],
|
32
36
|
"response" => params[:recaptcha_response_field]
|
33
37
|
}
|
34
|
-
Timeout::timeout(options[:timeout] ||
|
38
|
+
Timeout::timeout(options[:timeout] || DEFAULT_TIMEOUT) do
|
35
39
|
recaptcha = http.post_form(URI.parse(Recaptcha.configuration.verify_url), verify_hash)
|
36
40
|
end
|
37
41
|
answer, error = recaptcha.body.split.map { |s| s.chomp }
|
@@ -44,10 +48,10 @@ module Recaptcha
|
|
44
48
|
"response" => params['g-recaptcha-response']
|
45
49
|
}
|
46
50
|
|
47
|
-
Timeout::timeout(options[:timeout] ||
|
51
|
+
Timeout::timeout(options[:timeout] || DEFAULT_TIMEOUT) do
|
48
52
|
uri = URI.parse(Recaptcha.configuration.verify_url + '?' + verify_hash.to_query)
|
49
53
|
http_instance = http.new(uri.host, uri.port)
|
50
|
-
if uri.port==443
|
54
|
+
if uri.port == 443
|
51
55
|
http_instance.use_ssl =
|
52
56
|
http_instance.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
53
57
|
end
|
@@ -57,55 +61,56 @@ module Recaptcha
|
|
57
61
|
answer, error = JSON.parse(recaptcha.body).values
|
58
62
|
end
|
59
63
|
|
60
|
-
|
64
|
+
if answer.to_s == 'true'
|
65
|
+
flash.delete(:recaptcha_error) if request_in_html_format?
|
66
|
+
true
|
67
|
+
else
|
61
68
|
error = 'verification_failed' if error && Recaptcha.configuration.v2?
|
62
69
|
if request_in_html_format?
|
63
70
|
flash[:recaptcha_error] = if defined?(I18n)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
71
|
+
I18n.translate("recaptcha.errors.#{error}", default: error)
|
72
|
+
else
|
73
|
+
error
|
74
|
+
end
|
68
75
|
end
|
69
76
|
|
70
77
|
if model
|
71
78
|
message = "Word verification response is incorrect, please try again."
|
72
|
-
message = I18n.translate('recaptcha.errors.verification_failed',
|
79
|
+
message = I18n.translate('recaptcha.errors.verification_failed', default: message) if defined?(I18n)
|
73
80
|
model.errors.add attribute, options[:message] || message
|
74
81
|
end
|
75
|
-
|
76
|
-
else
|
77
|
-
flash.delete(:recaptcha_error) if request_in_html_format?
|
78
|
-
return true
|
82
|
+
false
|
79
83
|
end
|
80
84
|
rescue Timeout::Error
|
81
85
|
if Recaptcha.configuration.handle_timeouts_gracefully
|
82
86
|
if request_in_html_format?
|
83
87
|
flash[:recaptcha_error] = if defined?(I18n)
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
+
I18n.translate('recaptcha.errors.recaptcha_unreachable', default: 'Recaptcha unreachable.')
|
89
|
+
else
|
90
|
+
'Recaptcha unreachable.'
|
91
|
+
end
|
88
92
|
end
|
89
93
|
|
90
94
|
if model
|
91
95
|
message = "Oops, we failed to validate your word verification response. Please try again."
|
92
|
-
message = I18n.translate('recaptcha.errors.recaptcha_unreachable', :
|
96
|
+
message = I18n.translate('recaptcha.errors.recaptcha_unreachable', default: message) if defined?(I18n)
|
93
97
|
model.errors.add attribute, options[:message] || message
|
94
98
|
end
|
95
|
-
|
99
|
+
false
|
96
100
|
else
|
97
101
|
raise RecaptchaError, "Recaptcha unreachable."
|
98
102
|
end
|
99
|
-
rescue
|
103
|
+
rescue StandardError => e
|
100
104
|
raise RecaptchaError, e.message, e.backtrace
|
101
105
|
end
|
102
|
-
end
|
106
|
+
end
|
103
107
|
|
104
108
|
def request_in_html_format?
|
105
109
|
request.respond_to?(:format) && request.format == :html && respond_to?(:flash)
|
106
110
|
end
|
111
|
+
|
107
112
|
def verify_recaptcha!(options = {})
|
108
113
|
verify_recaptcha(options) or raise VerifyError
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/lib/recaptcha/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: recaptcha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.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
|
+
date: 2015-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: mocha
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,19 +81,19 @@ dependencies:
|
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
84
|
+
name: maxitest
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
|
-
- - "
|
87
|
+
- - ">="
|
74
88
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
89
|
+
version: '0'
|
76
90
|
type: :development
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
|
-
- - "
|
94
|
+
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: pry-byebug
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,37 +108,39 @@ dependencies:
|
|
94
108
|
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
97
|
-
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: bump
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: Helpers for the reCAPTCHA API
|
98
126
|
email:
|
99
127
|
- jasper@ambethia.com
|
100
128
|
executables: []
|
101
129
|
extensions: []
|
102
130
|
extra_rdoc_files: []
|
103
131
|
files:
|
104
|
-
- ".gitignore"
|
105
|
-
- ".travis.yml"
|
106
132
|
- CHANGELOG
|
107
|
-
- Gemfile
|
108
|
-
- Gemfile.lock
|
109
133
|
- LICENSE
|
110
|
-
- README.
|
111
|
-
- Rakefile
|
112
|
-
- init.rb
|
134
|
+
- README.md
|
113
135
|
- lib/recaptcha.rb
|
114
136
|
- lib/recaptcha/client_helper.rb
|
115
137
|
- lib/recaptcha/configuration.rb
|
116
|
-
- lib/recaptcha/merb.rb
|
117
138
|
- lib/recaptcha/rails.rb
|
118
|
-
- lib/recaptcha/railtie.rb
|
119
139
|
- lib/recaptcha/verify.rb
|
120
140
|
- 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
141
|
homepage: http://github.com/ambethia/recaptcha
|
127
|
-
licenses:
|
142
|
+
licenses:
|
143
|
+
- MIT
|
128
144
|
metadata: {}
|
129
145
|
post_install_message:
|
130
146
|
rdoc_options: []
|
@@ -134,20 +150,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
134
150
|
requirements:
|
135
151
|
- - ">="
|
136
152
|
- !ruby/object:Gem::Version
|
137
|
-
version:
|
153
|
+
version: 2.0.0
|
138
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
155
|
requirements:
|
140
156
|
- - ">="
|
141
157
|
- !ruby/object:Gem::Version
|
142
158
|
version: '0'
|
143
159
|
requirements: []
|
144
|
-
rubyforge_project:
|
145
|
-
rubygems_version: 2.4.5
|
160
|
+
rubyforge_project:
|
161
|
+
rubygems_version: 2.4.5.1
|
146
162
|
signing_key:
|
147
163
|
specification_version: 4
|
148
164
|
summary: Helpers for the reCAPTCHA API
|
149
|
-
test_files:
|
150
|
-
- test/recaptcha_configuration_test.rb
|
151
|
-
- test/recaptcha_test.rb
|
152
|
-
- test/recaptcha_v1_test.rb
|
153
|
-
- test/verify_recaptcha_test.rb
|
165
|
+
test_files: []
|
data/.gitignore
DELETED
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
recaptcha (0.4.0)
|
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/README.rdoc
DELETED
@@ -1,151 +0,0 @@
|
|
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
DELETED
data/init.rb
DELETED
data/lib/recaptcha/merb.rb
DELETED
data/lib/recaptcha/railtie.rb
DELETED
@@ -1,15 +0,0 @@
|
|
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
|
-
|
data/recaptcha.gemspec
DELETED
@@ -1,26 +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
|
-
s.add_development_dependency "minitest", "~> 5.0"
|
25
|
-
s.add_development_dependency "pry-byebug"
|
26
|
-
end
|
@@ -1,44 +0,0 @@
|
|
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
|
data/test/recaptcha_test.rb
DELETED
@@ -1,54 +0,0 @@
|
|
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
|
data/test/recaptcha_v1_test.rb
DELETED
@@ -1,35 +0,0 @@
|
|
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
|
@@ -1,191 +0,0 @@
|
|
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
|