rack-recaptcha 0.2.2 → 0.3.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.
- data/README.md +3 -3
- data/Rakefile +3 -48
- data/lib/rack/recaptcha.rb +17 -10
- data/lib/rack/recaptcha/helpers.rb +21 -0
- data/rack-recaptcha.gemspec +6 -5
- data/test/helpers_test.rb +43 -36
- data/test/recaptcha_test.rb +8 -7
- data/test/teststrap.rb +9 -1
- metadata +37 -15
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# rack-recaptcha
|
1
|
+
# rack-recaptcha [](http://stillmaintained.com/achiu/rack-recaptcha)
|
2
2
|
|
3
3
|
Drop this Rack middleware in your web application to enable CAPTCHA verification via Recaptcha API.
|
4
4
|
|
@@ -84,7 +84,7 @@ In Padrino, here's how you would use the helpers.
|
|
84
84
|
### Contributors
|
85
85
|
|
86
86
|
- Daniel Mendler(minad) - support for multiple paths and helpers clean up
|
87
|
-
|
87
|
+
- Eric Anderson(eric1234) - Make verify independently usable.
|
88
88
|
|
89
89
|
|
90
90
|
#### Note on Patches/Pull Requests
|
@@ -99,4 +99,4 @@ In Padrino, here's how you would use the helpers.
|
|
99
99
|
|
100
100
|
#### Copyright
|
101
101
|
|
102
|
-
Copyright (c)
|
102
|
+
Copyright (c) 2011 Arthur Chiu. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,25 +1,5 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
begin
|
5
|
-
require 'jeweler'
|
6
|
-
Jeweler::Tasks.new do |gem|
|
7
|
-
gem.name = "rack-recaptcha"
|
8
|
-
gem.summary = %Q{Rack middleware for Recaptcha}
|
9
|
-
gem.description = %Q{Rack middleware Captcha verification using Recaptcha API.}
|
10
|
-
gem.email = "mr.arthur.chiu@gmail.com"
|
11
|
-
gem.homepage = "http://github.com/achiu/rack-recaptcha"
|
12
|
-
gem.authors = ["Arthur Chiu"]
|
13
|
-
gem.add_runtime_dependency "json", ">=0"
|
14
|
-
gem.add_development_dependency "riot", ">= 0"
|
15
|
-
gem.add_development_dependency "rack-test", ">=0"
|
16
|
-
gem.add_development_dependency "rr", ">=0"
|
17
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
|
-
end
|
19
|
-
Jeweler::GemcutterTasks.new
|
20
|
-
rescue LoadError
|
21
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
22
|
-
end
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
23
3
|
|
24
4
|
require 'rake/testtask'
|
25
5
|
Rake::TestTask.new(:test) do |test|
|
@@ -28,29 +8,4 @@ Rake::TestTask.new(:test) do |test|
|
|
28
8
|
test.verbose = true
|
29
9
|
end
|
30
10
|
|
31
|
-
|
32
|
-
require 'rcov/rcovtask'
|
33
|
-
Rcov::RcovTask.new do |test|
|
34
|
-
test.libs << 'test'
|
35
|
-
test.pattern = 'test/**/*_test.rb'
|
36
|
-
test.verbose = true
|
37
|
-
end
|
38
|
-
rescue LoadError
|
39
|
-
task :rcov do
|
40
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
task :test => :check_dependencies
|
45
|
-
|
46
|
-
task :default => :test
|
47
|
-
|
48
|
-
require 'rake/rdoctask'
|
49
|
-
Rake::RDocTask.new do |rdoc|
|
50
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
51
|
-
|
52
|
-
rdoc.rdoc_dir = 'rdoc'
|
53
|
-
rdoc.title = "rack-recaptcha #{version}"
|
54
|
-
rdoc.rdoc_files.include('README*')
|
55
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
56
|
-
end
|
11
|
+
task :default => [:test]
|
data/lib/rack/recaptcha.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
-
require '
|
2
|
-
require 'rack/recaptcha/helpers'
|
1
|
+
require File.expand_path '../recaptcha/helpers', __FILE__
|
3
2
|
|
4
3
|
module Rack
|
5
4
|
class Recaptcha
|
6
|
-
API_URL = 'http://
|
7
|
-
API_SECURE_URL = 'https://
|
8
|
-
VERIFY_URL = 'http://
|
5
|
+
API_URL = 'http://www.google.com/recaptcha/api'
|
6
|
+
API_SECURE_URL = 'https://www.google.com/recaptcha/api'
|
7
|
+
VERIFY_URL = 'http://www.google.com/recaptcha/api/verify'
|
9
8
|
CHALLENGE_FIELD = 'recaptcha_challenge_field'
|
10
9
|
RESPONSE_FIELD = 'recaptcha_response_field'
|
11
10
|
|
@@ -13,6 +12,10 @@ module Rack
|
|
13
12
|
attr_accessor :private_key, :public_key
|
14
13
|
end
|
15
14
|
|
15
|
+
# Initialize the Rack Middleware. Some of the available options are:
|
16
|
+
# :public_key -- your ReCaptcha API public key *(required)*
|
17
|
+
# :private_key -- your ReCaptcha API private key *(required)*
|
18
|
+
# :paths -- where user goes to login or access the recaptcha (array of paths or single path)
|
16
19
|
def initialize(app,options = {})
|
17
20
|
@app = app
|
18
21
|
@paths = options[:paths] && [options[:paths]].flatten.compact
|
@@ -28,18 +31,22 @@ module Rack
|
|
28
31
|
request = Request.new(env)
|
29
32
|
if request.params[CHALLENGE_FIELD] and
|
30
33
|
request.params[RESPONSE_FIELD] and (not @paths or @paths.include?(request.path))
|
31
|
-
value, msg = verify(
|
34
|
+
value, msg = verify(
|
35
|
+
request.ip,
|
36
|
+
request.params[CHALLENGE_FIELD],
|
37
|
+
request.params[RESPONSE_FIELD]
|
38
|
+
)
|
32
39
|
env.merge!('recaptcha.valid' => value == 'true', 'recaptcha.msg' => msg)
|
33
40
|
end
|
34
41
|
@app.call(env)
|
35
42
|
end
|
36
43
|
|
37
|
-
def verify(
|
44
|
+
def verify(ip, challenge, response)
|
38
45
|
params = {
|
39
46
|
'privatekey' => Rack::Recaptcha.private_key,
|
40
|
-
'remoteip'
|
41
|
-
'challenge'
|
42
|
-
'response'
|
47
|
+
'remoteip' => ip,
|
48
|
+
'challenge' => challenge,
|
49
|
+
'response' => response
|
43
50
|
}
|
44
51
|
response = Net::HTTP.post_form URI.parse(VERIFY_URL), params
|
45
52
|
response.body.split("\n")
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
class Recaptcha
|
3
5
|
module Helpers
|
@@ -9,6 +11,24 @@ module Rack
|
|
9
11
|
:cols => 5
|
10
12
|
}
|
11
13
|
|
14
|
+
# Helper method to output a recaptcha form. Some of the available
|
15
|
+
# types you can have are:
|
16
|
+
#
|
17
|
+
# :challenge - Returns a javascript recaptcha form
|
18
|
+
# :noscript - Return a non-javascript recaptcha form
|
19
|
+
# :ajax - Return a ajax recaptcha form
|
20
|
+
#
|
21
|
+
# You also have a few available options:
|
22
|
+
#
|
23
|
+
# For :ajax:
|
24
|
+
# :display - You can adjust the display of the ajax form. An example:
|
25
|
+
# recaptcha_tag :ajax, :display => {:theme => 'red'}.
|
26
|
+
# For :challenge and :noscript
|
27
|
+
# :public_key - Set the public key. Overrides the key set in Middleware option
|
28
|
+
# :height - Adjust the height of the form
|
29
|
+
# :width - Adjust the width of the form
|
30
|
+
# :row - Adjust the rows for the challenge field
|
31
|
+
# :cols - Adjust the column for the challenge field
|
12
32
|
def recaptcha_tag(type= :noscript, options={})
|
13
33
|
options = DEFAULT.merge(options)
|
14
34
|
options[:public_key] ||= Rack::Recaptcha.public_key
|
@@ -41,6 +61,7 @@ module Rack
|
|
41
61
|
end + html
|
42
62
|
end
|
43
63
|
|
64
|
+
# Helper to return whether the recaptcha was accepted.
|
44
65
|
def recaptcha_valid?
|
45
66
|
request.env['recaptcha.valid']
|
46
67
|
end
|
data/rack-recaptcha.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = %q{rack-recaptcha}
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "0.3.0"
|
4
4
|
s.required_rubygems_version = ">=1.3.6"
|
5
5
|
s.authors = ["Arthur Chiu"]
|
6
6
|
s.date = %q{2010-07-18}
|
@@ -14,8 +14,9 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.rubygems_version = %q{1.3.7}
|
15
15
|
s.summary = %q{Rack middleware for Recaptcha}
|
16
16
|
s.test_files = Dir.glob("test/**/*")
|
17
|
-
s.add_runtime_dependency
|
18
|
-
s.add_development_dependency
|
19
|
-
s.add_development_dependency
|
20
|
-
s.add_development_dependency
|
17
|
+
s.add_runtime_dependency "json", ">= 0"
|
18
|
+
s.add_development_dependency "riot", "~> 0.12.1"
|
19
|
+
s.add_development_dependency "rack-test", "~> 0.5.7"
|
20
|
+
s.add_development_dependency "fakeweb", "~> 1.3.0"
|
21
|
+
s.add_development_dependency "rr", "~> 1.0.2"
|
21
22
|
end
|
data/test/helpers_test.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
require File.expand_path
|
2
|
-
require File.expand_path(File.join(File.dirname(__FILE__),'..','lib','rack','recaptcha','helpers'))
|
3
|
-
require 'riot/rr'
|
1
|
+
require File.expand_path '../teststrap', __FILE__
|
4
2
|
|
5
3
|
class HelperTest
|
6
4
|
attr_accessor :request
|
@@ -16,51 +14,60 @@ class HelperTest
|
|
16
14
|
end
|
17
15
|
|
18
16
|
context "Rack::Recaptcha::Helpers" do
|
19
|
-
setup
|
20
|
-
|
21
|
-
|
22
|
-
end
|
17
|
+
setup { Rack::Recaptcha.public_key = '0'*40 }
|
18
|
+
|
19
|
+
helper(:helper_test) { HelperTest.new }
|
23
20
|
|
24
21
|
|
25
22
|
context "recaptcha_tag" do
|
26
23
|
|
27
24
|
context "ajax" do
|
28
25
|
context "with display" do
|
29
|
-
setup {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
setup { helper_test.recaptcha_tag(:ajax,:display => {:theme => 'red'}) }
|
27
|
+
|
28
|
+
asserts_topic('has js').matches %r{recaptcha_ajax.js}
|
29
|
+
asserts_topic('has div').matches %r{<div id="ajax_recaptcha"></div>}
|
30
|
+
asserts_topic('has display').matches %r{RecaptchaOptions}
|
31
|
+
asserts_topic('has theme').matches %r{"theme":"red"}
|
34
32
|
end
|
35
33
|
context "without display" do
|
36
|
-
setup {
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
setup { helper_test.recaptcha_tag(:ajax) }
|
35
|
+
|
36
|
+
asserts_topic('has js').matches %r{recaptcha_ajax.js}
|
37
|
+
asserts_topic('has div').matches %r{<div id="ajax_recaptcha"></div>}
|
38
|
+
denies_topic('has display').matches %r{RecaptchaOptions}
|
39
|
+
denies_topic('has theme').matches %r{"theme":"red"}
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
44
43
|
context "noscript" do
|
45
|
-
setup {
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
44
|
+
setup { helper_test.recaptcha_tag :noscript, :public_key => "hello_world_world" }
|
45
|
+
|
46
|
+
asserts_topic("iframe").matches %r{iframe}
|
47
|
+
asserts_topic("no script tag").matches %r{<noscript>}
|
48
|
+
asserts_topic("public key").matches %r{hello_world_world}
|
49
|
+
denies_topic("has js").matches %r{recaptcha_ajax.js}
|
50
50
|
end
|
51
51
|
|
52
52
|
context "challenge" do
|
53
|
-
setup {
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
53
|
+
setup { helper_test.recaptcha_tag(:challenge) }
|
54
|
+
|
55
|
+
asserts_topic("has script tag").matches %r{script}
|
56
|
+
asserts_topic("has challenge js").matches %r{challenge}
|
57
|
+
denies_topic("has js").matches %r{recaptcha_ajax.js}
|
58
|
+
denies_topic("has display").matches %r{RecaptchaOptions}
|
59
|
+
asserts_topic("has public_key").matches %r{#{'0'*40}}
|
59
60
|
end
|
60
61
|
|
61
62
|
context "server" do
|
62
|
-
|
63
|
-
asserts("using
|
63
|
+
|
64
|
+
asserts("using ssl url") do
|
65
|
+
helper_test.recaptcha_tag(:challenge, :ssl => true)
|
66
|
+
end.matches %r{#{Rack::Recaptcha::API_SECURE_URL}}
|
67
|
+
|
68
|
+
asserts("using non ssl url") do
|
69
|
+
helper_test.recaptcha_tag(:ajax)
|
70
|
+
end.matches %r{#{Rack::Recaptcha::API_URL}}
|
64
71
|
end
|
65
72
|
|
66
73
|
end
|
@@ -69,18 +76,18 @@ context "Rack::Recaptcha::Helpers" do
|
|
69
76
|
|
70
77
|
context "passing" do
|
71
78
|
setup do
|
72
|
-
mock(
|
73
|
-
@helper.recaptcha_valid?
|
79
|
+
mock(helper_test.request.env).[]('recaptcha.valid').returns(true)
|
74
80
|
end
|
75
|
-
|
81
|
+
|
82
|
+
asserts("retrieves request") { helper_test.recaptcha_valid? }
|
76
83
|
end
|
77
84
|
|
78
85
|
context "failing" do
|
79
86
|
setup do
|
80
|
-
mock(
|
81
|
-
@helper.recaptcha_valid?
|
87
|
+
mock(helper_test.request.env).[]('recaptcha.valid').returns(false)
|
82
88
|
end
|
83
|
-
|
89
|
+
|
90
|
+
denies("that it retrieves request") { helper_test.recaptcha_valid? }
|
84
91
|
end
|
85
92
|
|
86
93
|
end
|
data/test/recaptcha_test.rb
CHANGED
@@ -1,19 +1,20 @@
|
|
1
|
-
require File.expand_path
|
2
|
-
require 'fakeweb'
|
1
|
+
require File.expand_path '../teststrap', __FILE__
|
3
2
|
|
4
3
|
FakeWeb.allow_net_connect = false
|
5
4
|
context "Rack::Recaptcha" do
|
6
5
|
|
7
6
|
context "basic request" do
|
8
|
-
setup { get("/")}
|
9
|
-
|
10
|
-
asserts(
|
7
|
+
setup { get("/") ; last_response }
|
8
|
+
|
9
|
+
asserts(:status).equals 200
|
10
|
+
asserts(:body).equals "Hello world"
|
11
11
|
end
|
12
12
|
|
13
13
|
context "exposes" do
|
14
14
|
setup { Rack::Recaptcha }
|
15
|
-
|
16
|
-
asserts(
|
15
|
+
|
16
|
+
asserts(:private_key).equals PRIVATE_KEY
|
17
|
+
asserts(:public_key).equals PUBLIC_KEY
|
17
18
|
end
|
18
19
|
|
19
20
|
context "login path" do
|
data/test/teststrap.rb
CHANGED
@@ -7,7 +7,8 @@ require 'rack/builder'
|
|
7
7
|
require 'rr'
|
8
8
|
require 'riot'
|
9
9
|
require 'riot/rr'
|
10
|
-
require
|
10
|
+
require 'fakeweb'
|
11
|
+
require File.expand_path '../../lib/rack/recaptcha', __FILE__
|
11
12
|
|
12
13
|
PUBLIC_KEY = '0'*40
|
13
14
|
PRIVATE_KEY = 'X'*40
|
@@ -38,5 +39,12 @@ class Riot::Situation
|
|
38
39
|
builder.run main_app
|
39
40
|
builder.to_app
|
40
41
|
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Riot::Context
|
41
45
|
|
46
|
+
# denies_topic currently on edge. Will remove once its released
|
47
|
+
def denies_topic(what)
|
48
|
+
denies(what) { topic }
|
49
|
+
end
|
42
50
|
end
|
metadata
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
name: rack-recaptcha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
hash: 19
|
5
|
-
prerelease:
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Arthur Chiu
|
@@ -38,12 +38,14 @@ dependencies:
|
|
38
38
|
requirement: &id002 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
|
-
- -
|
41
|
+
- - ~>
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
hash:
|
43
|
+
hash: 45
|
44
44
|
segments:
|
45
45
|
- 0
|
46
|
-
|
46
|
+
- 12
|
47
|
+
- 1
|
48
|
+
version: 0.12.1
|
47
49
|
type: :development
|
48
50
|
version_requirements: *id002
|
49
51
|
- !ruby/object:Gem::Dependency
|
@@ -52,28 +54,48 @@ dependencies:
|
|
52
54
|
requirement: &id003 !ruby/object:Gem::Requirement
|
53
55
|
none: false
|
54
56
|
requirements:
|
55
|
-
- -
|
57
|
+
- - ~>
|
56
58
|
- !ruby/object:Gem::Version
|
57
|
-
hash:
|
59
|
+
hash: 5
|
58
60
|
segments:
|
59
61
|
- 0
|
60
|
-
|
62
|
+
- 5
|
63
|
+
- 7
|
64
|
+
version: 0.5.7
|
61
65
|
type: :development
|
62
66
|
version_requirements: *id003
|
63
67
|
- !ruby/object:Gem::Dependency
|
64
|
-
name:
|
68
|
+
name: fakeweb
|
65
69
|
prerelease: false
|
66
70
|
requirement: &id004 !ruby/object:Gem::Requirement
|
67
71
|
none: false
|
68
72
|
requirements:
|
69
|
-
- -
|
73
|
+
- - ~>
|
70
74
|
- !ruby/object:Gem::Version
|
71
|
-
hash:
|
75
|
+
hash: 27
|
72
76
|
segments:
|
77
|
+
- 1
|
78
|
+
- 3
|
73
79
|
- 0
|
74
|
-
version:
|
80
|
+
version: 1.3.0
|
75
81
|
type: :development
|
76
82
|
version_requirements: *id004
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rr
|
85
|
+
prerelease: false
|
86
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ~>
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 19
|
92
|
+
segments:
|
93
|
+
- 1
|
94
|
+
- 0
|
95
|
+
- 2
|
96
|
+
version: 1.0.2
|
97
|
+
type: :development
|
98
|
+
version_requirements: *id005
|
77
99
|
description: Rack middleware Captcha verification using Recaptcha API.
|
78
100
|
email: mr.arthur.chiu@gmail.com
|
79
101
|
executables: []
|
@@ -127,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
149
|
requirements: []
|
128
150
|
|
129
151
|
rubyforge_project:
|
130
|
-
rubygems_version: 1.
|
152
|
+
rubygems_version: 1.6.1
|
131
153
|
signing_key:
|
132
154
|
specification_version: 3
|
133
155
|
summary: Rack middleware for Recaptcha
|