iGEL-ruby-recaptcha 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +11 -0
- data/README.textile +15 -0
- data/Rakefile +12 -0
- data/lib/recaptcha.rb +142 -0
- data/lib/ruby-recaptcha.rb +7 -0
- data/ruby-recaptcha.gemspec +32 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/test_helper.rb +3 -0
- data/test/test_recaptcha.rb +336 -0
- metadata +71 -0
data/Manifest
ADDED
data/README.textile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
h2. About this fork
|
2
|
+
|
3
|
+
This is my almost unchanged fork of "ruby-recaptcha":http://bitbucket.org/mml/ruby-recaptcha/wiki/Home See there for the original by McClain Looney and others.
|
4
|
+
|
5
|
+
I just want to change the error message, so I made it customable.
|
6
|
+
|
7
|
+
h2. License
|
8
|
+
|
9
|
+
Copyright (c) 2009 McClain Looney
|
10
|
+
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
Echoe.new('ruby-recaptcha', "1.0.0") do |p|
|
6
|
+
p.description = "My almost unchanged fork of ruby-recaptcha"
|
7
|
+
p.url = "http://bitbucket.org/mml/ruby-recaptcha/wiki/Home"
|
8
|
+
p.author = "Johannes Barre"
|
9
|
+
p.email = "igel@igels.net"
|
10
|
+
p.ignore_pattern = ["pkg/*", "logs/*", "output*", "nbproject/**", "nbproject/private/*"]
|
11
|
+
p.development_dependencies = []
|
12
|
+
end
|
data/lib/recaptcha.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
#Copyright (c) 2007, 2008, 2009 McClain Looney
|
2
|
+
#
|
3
|
+
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
#of this software and associated documentation files (the "Software"), to deal
|
5
|
+
#in the Software without restriction, including without limitation the rights
|
6
|
+
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
#copies of the Software, and to permit persons to whom the Software is
|
8
|
+
#furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
#The above copyright notice and this permission notice shall be included in
|
11
|
+
#all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
#THE SOFTWARE.
|
20
|
+
require 'openssl'
|
21
|
+
require 'base64'
|
22
|
+
require 'cgi'
|
23
|
+
require 'net/http'
|
24
|
+
require 'net/https'
|
25
|
+
module ReCaptcha
|
26
|
+
module ViewHelper
|
27
|
+
def get_captcha(options={})
|
28
|
+
k = ReCaptcha::Client.new(options[:rcc_pub] || RCC_PUB, options[:rcc_priv] || RCC_PRIV, options[:ssl] || false)
|
29
|
+
r = k.get_challenge(session[:rcc_err] || '', options)
|
30
|
+
session[:rcc_err]=''
|
31
|
+
r
|
32
|
+
end
|
33
|
+
def mail_hide(address, contents=nil)
|
34
|
+
contents = truncate(address,10) if contents.nil?
|
35
|
+
k = ReCaptcha::MHClient.new(MH_PUB, MH_PRIV)
|
36
|
+
enciphered = k.encrypt(address)
|
37
|
+
uri = "http://mailhide.recaptcha.net/d?k=#{MH_PUB}&c=#{enciphered}"
|
38
|
+
t =<<-EOF
|
39
|
+
<a href="#{uri}"
|
40
|
+
onclick="window.open('#{uri}', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;" title="Reveal this e-mail address">#{contents}</a>
|
41
|
+
EOF
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
module AppHelper
|
46
|
+
private
|
47
|
+
def validate_recap(p, errors, options = {:msg => "Captcha failed."})
|
48
|
+
rcc=ReCaptcha::Client.new(options[:rcc_pub] || RCC_PUB, options[:rcc_priv] || RCC_PRIV)
|
49
|
+
res = rcc.validate(request.remote_ip, p[:recaptcha_challenge_field], p[:recaptcha_response_field], errors, options[:msg])
|
50
|
+
session[:rcc_err]=rcc.last_error
|
51
|
+
|
52
|
+
res
|
53
|
+
end
|
54
|
+
end
|
55
|
+
class MHClient
|
56
|
+
def initialize(pubkey, privkey)
|
57
|
+
@pubkey=pubkey
|
58
|
+
@privkey=privkey
|
59
|
+
@host='mailhide.recaptcha.net'
|
60
|
+
end
|
61
|
+
def encrypt(string)
|
62
|
+
padded = pad(string)
|
63
|
+
iv="\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
|
64
|
+
cipher=OpenSSL::Cipher::Cipher.new("AES-128-CBC")
|
65
|
+
binkey = @privkey.unpack('a2'*16).map{|x| x.hex}.pack('c'*16)
|
66
|
+
cipher.encrypt
|
67
|
+
cipher.key=binkey
|
68
|
+
cipher.iv=iv
|
69
|
+
ciphertext = []
|
70
|
+
cipher.padding=0
|
71
|
+
ciphertext = cipher.update(padded)
|
72
|
+
ciphertext << cipher.final() rescue nil
|
73
|
+
Base64.encode64(ciphertext).strip.gsub(/\+/, '-').gsub(/\//, '_').gsub(/\n/,'')
|
74
|
+
end
|
75
|
+
def pad(str)
|
76
|
+
l= 16-(str.length%16)
|
77
|
+
l.times do
|
78
|
+
str<< l
|
79
|
+
end
|
80
|
+
str
|
81
|
+
end
|
82
|
+
end
|
83
|
+
class Client
|
84
|
+
|
85
|
+
def initialize(pubkey, privkey, ssl=false)
|
86
|
+
@pubkey = pubkey
|
87
|
+
@privkey=privkey
|
88
|
+
@host = ssl ? 'api-secure.recaptcha.net':'api.recaptcha.net'
|
89
|
+
@vhost = 'api-verify.recaptcha.net'
|
90
|
+
@proto = ssl ? 'https' : 'http'
|
91
|
+
@ssl = ssl
|
92
|
+
@last_error=nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_challenge(error='', options={})
|
96
|
+
s=''
|
97
|
+
if options[:options]
|
98
|
+
s << "<script type=\"text/javascript\">\nvar RecaptchaOptions = { "
|
99
|
+
options[:options].each do |k,v|
|
100
|
+
val = (v.class == Fixnum) ? "#{v}" : "\"#{v}\""
|
101
|
+
s << "#{k} : #{val}, "
|
102
|
+
end
|
103
|
+
s.sub!(/, $/, '};')
|
104
|
+
s << "\n</script>\n"
|
105
|
+
end
|
106
|
+
errslug = (error.empty?||error==nil||error=="success") ? '' : "&error=#{CGI.escape(error)}"
|
107
|
+
s <<<<-EOF
|
108
|
+
<script type="text/javascript" src="#{@proto}://#{@host}/challenge?k=#{CGI.escape(@pubkey)}#{errslug}"> </script>
|
109
|
+
<noscript>
|
110
|
+
<iframe src="#{@proto}://#{@host}/noscript?k=#{CGI.escape(@pubkey)}#{errslug}"
|
111
|
+
height="300" width="500" frameborder="0"></iframe><br>
|
112
|
+
<textarea name="recaptcha_challenge_field" rows="3" cols="40">
|
113
|
+
</textarea>
|
114
|
+
<input type="hidden" name="recaptcha_response_field"
|
115
|
+
value="manual_challenge">
|
116
|
+
</noscript>
|
117
|
+
EOF
|
118
|
+
end
|
119
|
+
|
120
|
+
def last_error
|
121
|
+
@last_error
|
122
|
+
end
|
123
|
+
def validate(remoteip, challenge, response, errors, msg)
|
124
|
+
unless response and challenge
|
125
|
+
errors.add_to_base(msg)
|
126
|
+
return false
|
127
|
+
end
|
128
|
+
proxy_host, proxy_port = nil, nil
|
129
|
+
proxy_host, proxy_port = ENV['proxy_host'].split(':') if ENV.has_key?('proxy_host')
|
130
|
+
http = Net::HTTP::Proxy(proxy_host, proxy_port).start(@vhost)
|
131
|
+
path='/verify'
|
132
|
+
data = "privatekey=#{CGI.escape(@privkey)}&remoteip=#{CGI.escape(remoteip)}&challenge=#{CGI.escape(challenge)}&response=#{CGI.escape(response)}"
|
133
|
+
resp, data = http.post(path, data, {'Content-Type'=>'application/x-www-form-urlencoded'})
|
134
|
+
response = data.split
|
135
|
+
result = response[0].chomp
|
136
|
+
@last_error=response[1].chomp
|
137
|
+
errors.add_to_base(msg) if result != 'true'
|
138
|
+
result == 'true'
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{ruby-recaptcha}
|
5
|
+
s.version = "1.0.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Johannes Barre"]
|
9
|
+
s.date = %q{2009-03-16}
|
10
|
+
s.description = %q{My almost unchanged fork of ruby-recaptcha}
|
11
|
+
s.email = %q{igel@igels.net}
|
12
|
+
s.extra_rdoc_files = ["lib/recaptcha.rb", "lib/ruby-recaptcha.rb", "README.textile"]
|
13
|
+
s.files = ["Manifest", "Rakefile", "test/test_recaptcha.rb", "test/test_helper.rb", "script/console", "script/generate", "script/destroy", "lib/recaptcha.rb", "lib/ruby-recaptcha.rb", "README.textile", "ruby-recaptcha.gemspec"]
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.homepage = %q{http://bitbucket.org/mml/ruby-recaptcha/wiki/Home}
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Ruby-recaptcha", "--main", "README.textile"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{ruby-recaptcha}
|
19
|
+
s.rubygems_version = %q{1.3.1}
|
20
|
+
s.summary = %q{My almost unchanged fork of ruby-recaptcha}
|
21
|
+
s.test_files = ["test/test_recaptcha.rb", "test/test_helper.rb"]
|
22
|
+
|
23
|
+
if s.respond_to? :specification_version then
|
24
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
25
|
+
s.specification_version = 2
|
26
|
+
|
27
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
28
|
+
else
|
29
|
+
end
|
30
|
+
else
|
31
|
+
end
|
32
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/ruby-recaptcha.rb'}"
|
9
|
+
puts "Loading ruby-recaptcha gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,336 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
require 'rubygems'
|
3
|
+
gem 'mocha'
|
4
|
+
require 'mocha'
|
5
|
+
gem 'rails'
|
6
|
+
|
7
|
+
module ReCaptcha
|
8
|
+
module ViewHelper
|
9
|
+
def self.define_public_key
|
10
|
+
class_eval "RCC_PUB = 'foo'"
|
11
|
+
end
|
12
|
+
def self.define_private_key
|
13
|
+
class_eval "RCC_PRIV = 'bar'"
|
14
|
+
end
|
15
|
+
def self.undefine_public_key
|
16
|
+
remove_const :RCC_PUB
|
17
|
+
end
|
18
|
+
def self.undefine_private_key
|
19
|
+
remove_const :RCC_PRIV
|
20
|
+
end
|
21
|
+
end
|
22
|
+
module AppHelper
|
23
|
+
def self.define_public_key
|
24
|
+
class_eval "RCC_PUB = 'foo'"
|
25
|
+
end
|
26
|
+
def self.define_private_key
|
27
|
+
class_eval "RCC_PRIV = 'bar'"
|
28
|
+
end
|
29
|
+
def self.undefine_public_key
|
30
|
+
remove_const :RCC_PUB
|
31
|
+
end
|
32
|
+
def self.undefine_private_key
|
33
|
+
remove_const :RCC_PRIV
|
34
|
+
end
|
35
|
+
public :validate_recap
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class TestRecaptcha < Test::Unit::TestCase
|
40
|
+
class ViewFixture
|
41
|
+
PRIVKEY='6LdnAQAAAAAAAPYLVPwVvR7Cy9YLhRQcM3NWsK_C'
|
42
|
+
PUBKEY='6LdnAQAAAAAAAKEk59yjuP3csGEeDmdj__7cyMtY'
|
43
|
+
include ReCaptcha::ViewHelper
|
44
|
+
# views in Rails "inherit" the controller's session...
|
45
|
+
def session
|
46
|
+
@session ||= {}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
class ControllerFixture
|
50
|
+
include ReCaptcha::AppHelper
|
51
|
+
attr_reader :request
|
52
|
+
# all Rails controllers have a session...
|
53
|
+
def session
|
54
|
+
@session ||= {}
|
55
|
+
end
|
56
|
+
def initialize()
|
57
|
+
@request = mock()
|
58
|
+
@request.stubs(:remote_ip).returns('0.0.0.0') # this will skip the actual captcha validation...
|
59
|
+
@request
|
60
|
+
end
|
61
|
+
include Mocha::Standalone
|
62
|
+
end
|
63
|
+
|
64
|
+
def setup
|
65
|
+
@vf = ViewFixture.new
|
66
|
+
@cf = ControllerFixture.new
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_encrypt
|
70
|
+
mhc = ReCaptcha::MHClient.new('01S1TOX9aibKxfC9oJlp8IeA==', 'deadbeefdeadbeefdeadbeefdeadbeef')
|
71
|
+
z =mhc.encrypt('x@example.com')
|
72
|
+
assert_equal 'wBG7nOgntKqWeDpF9ucVNQ==', z
|
73
|
+
z =mhc.encrypt('johndoe@example.com')
|
74
|
+
assert_equal 'whWIqk0r4urZ-3S7y7uSceC9_ECd3hpAGy71E2o0HpI=', z
|
75
|
+
end
|
76
|
+
def test_encrypt_long
|
77
|
+
mhc = ReCaptcha::MHClient.new('01S1TOX9aibKxfC9oJlp8IeA==', 'deadbeefdeadbeefdeadbeefdeadbeef')
|
78
|
+
z =mhc.encrypt('averylongemailaddressofmorethan32cdharactersx@example.com')
|
79
|
+
assert_equal "q-0LLVT2bIxWbFpfLfpNhJAGadkfWXVk4hAxSlVaLrdnXrsB1NKNubavS5N-7PBued3K531vifN6NB3iz3W7qQ==",z
|
80
|
+
z =mhc.encrypt('johndoe@example.com')
|
81
|
+
assert_equal 'whWIqk0r4urZ-3S7y7uSceC9_ECd3hpAGy71E2o0HpI=', z
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_nil_challenge
|
85
|
+
client = new_client
|
86
|
+
estub = stub_everything('errors')
|
87
|
+
client.validate('abc', nil, 'foo', estub)
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_constructor
|
92
|
+
client = new_client('abc', 'def', true)
|
93
|
+
expected= <<-EOF
|
94
|
+
<script type=\"text/javascript\" src=\"https://api-secure.recaptcha.net/challenge?k=abc\"> </script>\n <noscript>\n <iframe src=\"https://api-secure.recaptcha.net/noscript?k=abc\"\n height=\"300\" width=\"500\" frameborder=\"0\"></iframe><br>\n <textarea name=\"recaptcha_challenge_field\" rows=\"3\" cols=\"40\">\n </textarea>\n <input type=\"hidden\" name=\"recaptcha_response_field\" \n value=\"manual_challenge\">\n </noscript>
|
95
|
+
EOF
|
96
|
+
assert_equal expected.strip, client.get_challenge.strip
|
97
|
+
client = new_client
|
98
|
+
expected= <<-EOF
|
99
|
+
<script type=\"text/javascript\" src=\"http://api.recaptcha.net/challenge?k=abc\"> </script>\n <noscript>\n <iframe src=\"http://api.recaptcha.net/noscript?k=abc\"\n height=\"300\" width=\"500\" frameborder=\"0\"></iframe><br>\n <textarea name=\"recaptcha_challenge_field\" rows=\"3\" cols=\"40\">\n </textarea>\n <input type=\"hidden\" name=\"recaptcha_response_field\" \n value=\"manual_challenge\">\n </noscript>
|
100
|
+
EOF
|
101
|
+
assert_equal expected.strip, client.get_challenge.strip
|
102
|
+
client = new_client
|
103
|
+
expected= <<-EOF
|
104
|
+
<script type=\"text/javascript\" src=\"http://api.recaptcha.net/challenge?k=abc\"> </script>\n <noscript>\n <iframe src=\"http://api.recaptcha.net/noscript?k=abc\"\n height=\"300\" width=\"500\" frameborder=\"0\"></iframe><br>\n <textarea name=\"recaptcha_challenge_field\" rows=\"3\" cols=\"40\">\n </textarea>\n <input type=\"hidden\" name=\"recaptcha_response_field\" \n value=\"manual_challenge\">\n </noscript>
|
105
|
+
EOF
|
106
|
+
assert_equal expected.strip, client.get_challenge.strip
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_constructor_with_recaptcha_options
|
110
|
+
# "Look and Feel Customization" per http://recaptcha.net/apidocs/captcha/
|
111
|
+
client = new_client
|
112
|
+
expected= <<-EOF
|
113
|
+
<script type=\"text/javascript\">\nvar RecaptchaOptions = { theme : \"white\", tabindex : 10};\n</script>\n <script type=\"text/javascript\" src=\"http://api.recaptcha.net/challenge?k=abc&error=somerror\"> </script>\n <noscript>\n <iframe src=\"http://api.recaptcha.net/noscript?k=abc&error=somerror\"\n height=\"300\" width=\"500\" frameborder=\"0\"></iframe><br>\n <textarea name=\"recaptcha_challenge_field\" rows=\"3\" cols=\"40\">\n </textarea>\n <input type=\"hidden\" name=\"recaptcha_response_field\" \n value=\"manual_challenge\">\n </noscript>
|
114
|
+
EOF
|
115
|
+
assert_equal expected.strip, client.get_challenge('somerror', :options => {:theme => 'white', :tabindex => 10}).strip
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_validate_fails
|
119
|
+
badwords_resp="false\r\n360 incorrect-captcha-sol"
|
120
|
+
err_stub=mock()
|
121
|
+
err_stub.expects(:add_to_base).with("Captcha failed.")
|
122
|
+
stub_proxy=mock('proxy')
|
123
|
+
stub_http = mock('http mock')
|
124
|
+
stub_proxy.expects(:start).with('api-verify.recaptcha.net').returns(stub_http)
|
125
|
+
stub_http.expects(:post).with('/verify', 'privatekey=def&remoteip=localhost&challenge=abc&response=def', {'Content-Type' => 'application/x-www-form-urlencoded'}).returns(['foo', badwords_resp])
|
126
|
+
Net::HTTP.expects(:Proxy).returns(stub_proxy)
|
127
|
+
client = new_client
|
128
|
+
assert !client.validate('localhost', 'abc', 'def', err_stub)
|
129
|
+
end
|
130
|
+
def test_validate_good
|
131
|
+
goodwords_resp="true\r\nsuccess"
|
132
|
+
err_stub=mock()
|
133
|
+
stub_proxy=mock('proxy')
|
134
|
+
stub_http = mock('http mock')
|
135
|
+
stub_proxy.expects(:start).with('api-verify.recaptcha.net').returns(stub_http)
|
136
|
+
stub_http.expects(:post).with('/verify', 'privatekey=def&remoteip=localhost&challenge=abc&response=def', {'Content-Type' => 'application/x-www-form-urlencoded'}).returns(['foo', goodwords_resp])
|
137
|
+
Net::HTTP.expects(:Proxy).with(nil, nil).returns(stub_proxy)
|
138
|
+
client = new_client
|
139
|
+
assert client.validate('localhost', 'abc', 'def', err_stub)
|
140
|
+
end
|
141
|
+
def test_validate_good_proxy
|
142
|
+
ENV['proxy_host']='fubar:8080'
|
143
|
+
goodwords_resp="true\r\nsuccess"
|
144
|
+
err_stub=mock()
|
145
|
+
stub_proxy=mock('proxy')
|
146
|
+
stub_http = mock('http mock')
|
147
|
+
stub_proxy.expects(:start).with('api-verify.recaptcha.net').returns(stub_http)
|
148
|
+
stub_http.expects(:post).with('/verify', 'privatekey=def&remoteip=localhost&challenge=abc&response=def', {'Content-Type' => 'application/x-www-form-urlencoded'}).returns(['foo', goodwords_resp])
|
149
|
+
Net::HTTP.expects(:Proxy).with('fubar', '8080').returns(stub_proxy)
|
150
|
+
client = new_client
|
151
|
+
assert client.validate('localhost', 'abc', 'def', err_stub)
|
152
|
+
ENV['proxy_host']='fubar'
|
153
|
+
err_stub=mock()
|
154
|
+
stub_proxy=mock('proxy')
|
155
|
+
stub_http = mock('http mock')
|
156
|
+
stub_proxy.expects(:start).with('api-verify.recaptcha.net').returns(stub_http)
|
157
|
+
stub_http.expects(:post).with('/verify', 'privatekey=def&remoteip=localhost&challenge=abc&response=def', {'Content-Type' => 'application/x-www-form-urlencoded'}).returns(['foo', goodwords_resp])
|
158
|
+
Net::HTTP.expects(:Proxy).with('fubar', nil).returns(stub_proxy)
|
159
|
+
client = new_client
|
160
|
+
assert client.validate('localhost', 'abc', 'def', err_stub)
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# unit tests for the get_captcha() ViewHelper method
|
165
|
+
#
|
166
|
+
|
167
|
+
def test_get_captcha_fails_without_key_constants
|
168
|
+
assert !ReCaptcha::ViewHelper.const_defined?(:RCC_PUB)
|
169
|
+
assert !ReCaptcha::ViewHelper.const_defined?(:RCC_PRIV)
|
170
|
+
assert_raise NameError do
|
171
|
+
@vf.get_captcha
|
172
|
+
end
|
173
|
+
end
|
174
|
+
def test_get_captcha_fails_without_public_key_constant
|
175
|
+
assert !ReCaptcha::ViewHelper.const_defined?(:RCC_PUB)
|
176
|
+
assert !ReCaptcha::ViewHelper.const_defined?(:RCC_PRIV)
|
177
|
+
ReCaptcha::ViewHelper.define_private_key
|
178
|
+
assert ReCaptcha::ViewHelper.const_defined?(:RCC_PRIV)
|
179
|
+
assert_raise NameError do
|
180
|
+
@vf.get_captcha
|
181
|
+
end
|
182
|
+
ReCaptcha::ViewHelper.undefine_private_key
|
183
|
+
end
|
184
|
+
def test_get_captcha_fails_without_private_key_constant
|
185
|
+
assert !ReCaptcha::ViewHelper.const_defined?(:RCC_PUB)
|
186
|
+
assert !ReCaptcha::ViewHelper.const_defined?(:RCC_PRIV)
|
187
|
+
ReCaptcha::ViewHelper.define_public_key
|
188
|
+
assert ReCaptcha::ViewHelper.const_defined?(:RCC_PUB)
|
189
|
+
assert_raise NameError do
|
190
|
+
@vf.get_captcha
|
191
|
+
end
|
192
|
+
ReCaptcha::ViewHelper.undefine_public_key
|
193
|
+
end
|
194
|
+
def test_get_captcha_succeeds_with_key_constants
|
195
|
+
mock_client = mock('client')
|
196
|
+
ReCaptcha::Client.expects(:new).returns(mock_client)
|
197
|
+
mock_client.expects(:get_challenge).with('', {})
|
198
|
+
assert !ReCaptcha::ViewHelper.const_defined?(:RCC_PUB)
|
199
|
+
assert !ReCaptcha::ViewHelper.const_defined?(:RCC_PRIV)
|
200
|
+
ReCaptcha::ViewHelper.define_public_key
|
201
|
+
ReCaptcha::ViewHelper.define_private_key
|
202
|
+
assert ReCaptcha::ViewHelper.const_defined?(:RCC_PUB)
|
203
|
+
assert ReCaptcha::ViewHelper.const_defined?(:RCC_PRIV)
|
204
|
+
assert_nothing_raised do
|
205
|
+
@vf.get_captcha
|
206
|
+
end
|
207
|
+
ReCaptcha::ViewHelper.undefine_public_key
|
208
|
+
ReCaptcha::ViewHelper.undefine_private_key
|
209
|
+
end
|
210
|
+
def test_get_captcha_succeeds_without_key_constants_but_with_options
|
211
|
+
assert !ReCaptcha::ViewHelper.const_defined?(:RCC_PUB)
|
212
|
+
assert !ReCaptcha::ViewHelper.const_defined?(:RCC_PRIV)
|
213
|
+
assert_nothing_raised do
|
214
|
+
@vf.get_captcha(:rcc_pub => 'foo', :rcc_priv => 'bar')
|
215
|
+
end
|
216
|
+
end
|
217
|
+
def test_get_captcha_is_correct_with_constants_and_with_options
|
218
|
+
expected= <<-EOF
|
219
|
+
<script type=\"text/javascript\" src=\"http://api.recaptcha.net/challenge?k=%s\"> </script>\n <noscript>\n <iframe src=\"http://api.recaptcha.net/noscript?k=%s\"\n height=\"300\" width=\"500\" frameborder=\"0\"></iframe><br>\n <textarea name=\"recaptcha_challenge_field\" rows=\"3\" cols=\"40\">\n </textarea>\n <input type=\"hidden\" name=\"recaptcha_response_field\" \n value=\"manual_challenge\">\n </noscript>
|
220
|
+
EOF
|
221
|
+
# first, with constants
|
222
|
+
ReCaptcha::ViewHelper.define_public_key # 'foo'
|
223
|
+
ReCaptcha::ViewHelper.define_private_key # 'bar'
|
224
|
+
actual = @vf.get_captcha
|
225
|
+
assert_equal(((expected % ['foo', 'foo']).strip), actual.strip)
|
226
|
+
ReCaptcha::ViewHelper.undefine_public_key
|
227
|
+
ReCaptcha::ViewHelper.undefine_private_key
|
228
|
+
# next, with options
|
229
|
+
actual = @vf.get_captcha(:rcc_pub => 'foobar', :rcc_priv => 'blegga')
|
230
|
+
assert_equal(((expected % ['foobar', 'foobar']).strip), actual.strip)
|
231
|
+
end
|
232
|
+
|
233
|
+
#
|
234
|
+
# unit tests for the validate_recap() AppHelper method
|
235
|
+
#
|
236
|
+
|
237
|
+
def test_validate_recap_fails_without_key_constants
|
238
|
+
assert !ReCaptcha::AppHelper.const_defined?(:RCC_PUB)
|
239
|
+
assert !ReCaptcha::AppHelper.const_defined?(:RCC_PRIV)
|
240
|
+
assert_raise NameError do
|
241
|
+
@cf.validate_recap({}, {})
|
242
|
+
end
|
243
|
+
end
|
244
|
+
def test_validate_recap_fails_without_public_key_constant
|
245
|
+
assert !ReCaptcha::AppHelper.const_defined?(:RCC_PUB)
|
246
|
+
assert !ReCaptcha::AppHelper.const_defined?(:RCC_PRIV)
|
247
|
+
ReCaptcha::AppHelper.define_private_key
|
248
|
+
assert ReCaptcha::AppHelper.const_defined?(:RCC_PRIV)
|
249
|
+
assert_raise NameError do
|
250
|
+
@cf.validate_recap({}, {})
|
251
|
+
end
|
252
|
+
ReCaptcha::AppHelper.undefine_private_key
|
253
|
+
end
|
254
|
+
def test_validate_recap_fails_without_private_key_constant
|
255
|
+
assert !ReCaptcha::AppHelper.const_defined?(:RCC_PUB)
|
256
|
+
assert !ReCaptcha::AppHelper.const_defined?(:RCC_PRIV)
|
257
|
+
ReCaptcha::AppHelper.define_public_key
|
258
|
+
assert ReCaptcha::AppHelper.const_defined?(:RCC_PUB)
|
259
|
+
assert_raise NameError do
|
260
|
+
@cf.validate_recap({}, {})
|
261
|
+
end
|
262
|
+
ReCaptcha::AppHelper.undefine_public_key
|
263
|
+
end
|
264
|
+
def test_validate_recap_succeeds_with_key_constants
|
265
|
+
e = mock('errors')
|
266
|
+
e.expects(:add_to_base).with('Captcha failed.')
|
267
|
+
assert !ReCaptcha::AppHelper.const_defined?(:RCC_PUB)
|
268
|
+
assert !ReCaptcha::AppHelper.const_defined?(:RCC_PRIV)
|
269
|
+
ReCaptcha::AppHelper.define_public_key
|
270
|
+
ReCaptcha::AppHelper.define_private_key
|
271
|
+
assert ReCaptcha::AppHelper.const_defined?(:RCC_PUB)
|
272
|
+
assert ReCaptcha::AppHelper.const_defined?(:RCC_PRIV)
|
273
|
+
assert_nothing_raised do
|
274
|
+
@cf.validate_recap({}, e)
|
275
|
+
end
|
276
|
+
ReCaptcha::AppHelper.undefine_public_key
|
277
|
+
ReCaptcha::AppHelper.undefine_private_key
|
278
|
+
end
|
279
|
+
def test_validate_recap_succeeds_without_key_constants_but_with_options
|
280
|
+
mock = mock('client')
|
281
|
+
ReCaptcha::Client.expects(:new).returns(mock)
|
282
|
+
mock.expects(:validate).with('0.0.0.0', nil, nil, {}).returns(true)
|
283
|
+
mock.expects(:last_error)
|
284
|
+
assert !ReCaptcha::AppHelper.const_defined?(:RCC_PUB)
|
285
|
+
assert !ReCaptcha::AppHelper.const_defined?(:RCC_PRIV)
|
286
|
+
@cf.validate_recap({}, {}, :rcc_pub => 'foo', :rcc_priv => 'bar')
|
287
|
+
end
|
288
|
+
def test_validate_recap_is_correct_with_constants_and_with_options
|
289
|
+
# first, with constants
|
290
|
+
e = mock('errors')
|
291
|
+
mock = mock('client')
|
292
|
+
ReCaptcha::Client.expects(:new).returns(mock).times(2)
|
293
|
+
mock.expects(:validate).with('0.0.0.0', nil, nil, {}).returns(true)
|
294
|
+
mock.expects(:last_error).times(2)
|
295
|
+
ReCaptcha::AppHelper.define_public_key # 'foo'
|
296
|
+
ReCaptcha::AppHelper.define_private_key # 'bar'
|
297
|
+
assert @cf.validate_recap({}, {})
|
298
|
+
ReCaptcha::AppHelper.undefine_public_key
|
299
|
+
ReCaptcha::AppHelper.undefine_private_key
|
300
|
+
# next, with options
|
301
|
+
mock.expects(:validate).with('0.0.0.0', nil, nil, e).returns(true)
|
302
|
+
assert @cf.validate_recap({}, e, {:rcc_pub => 'foobar', :rcc_priv => 'blegga'})
|
303
|
+
end
|
304
|
+
|
305
|
+
#
|
306
|
+
# unit tests for HTTP/HTTPS-variants of get_captcha() method
|
307
|
+
#
|
308
|
+
|
309
|
+
def test_get_captcha_uses_http_without_options
|
310
|
+
expected= <<-EOF
|
311
|
+
<script type=\"text/javascript\" src=\"http://api.recaptcha.net/challenge?k=%s\"> </script>\n <noscript>\n <iframe src=\"http://api.recaptcha.net/noscript?k=%s\"\n height=\"300\" width=\"500\" frameborder=\"0\"></iframe><br>\n <textarea name=\"recaptcha_challenge_field\" rows=\"3\" cols=\"40\">\n </textarea>\n <input type=\"hidden\" name=\"recaptcha_response_field\" \n value=\"manual_challenge\">\n </noscript>
|
312
|
+
EOF
|
313
|
+
actual = @vf.get_captcha(:rcc_pub => 'foobar', :rcc_priv => 'blegga')
|
314
|
+
assert_equal(((expected % ['foobar', 'foobar']).strip), actual.strip)
|
315
|
+
end
|
316
|
+
def test_get_captcha_uses_https_with_options_true
|
317
|
+
expected= <<-EOF
|
318
|
+
<script type=\"text/javascript\" src=\"https://api-secure.recaptcha.net/challenge?k=%s\"> </script>\n <noscript>\n <iframe src=\"https://api-secure.recaptcha.net/noscript?k=%s\"\n height=\"300\" width=\"500\" frameborder=\"0\"></iframe><br>\n <textarea name=\"recaptcha_challenge_field\" rows=\"3\" cols=\"40\">\n </textarea>\n <input type=\"hidden\" name=\"recaptcha_response_field\" \n value=\"manual_challenge\">\n </noscript>
|
319
|
+
EOF
|
320
|
+
actual = @vf.get_captcha(:rcc_pub => 'foobar', :rcc_priv => 'blegga', :ssl => true)
|
321
|
+
assert_equal(((expected % ['foobar', 'foobar']).strip), actual.strip)
|
322
|
+
end
|
323
|
+
def test_get_captcha_uses_http_with_options_false
|
324
|
+
expected= <<-EOF
|
325
|
+
<script type=\"text/javascript\" src=\"http://api.recaptcha.net/challenge?k=%s\"> </script>\n <noscript>\n <iframe src=\"http://api.recaptcha.net/noscript?k=%s\"\n height=\"300\" width=\"500\" frameborder=\"0\"></iframe><br>\n <textarea name=\"recaptcha_challenge_field\" rows=\"3\" cols=\"40\">\n </textarea>\n <input type=\"hidden\" name=\"recaptcha_response_field\" \n value=\"manual_challenge\">\n </noscript>
|
326
|
+
EOF
|
327
|
+
actual = @vf.get_captcha(:rcc_pub => 'foobar', :rcc_priv => 'blegga', :ssl => false)
|
328
|
+
assert_equal(((expected % ['foobar', 'foobar']).strip), actual.strip)
|
329
|
+
end
|
330
|
+
|
331
|
+
private
|
332
|
+
|
333
|
+
def new_client(pubkey='abc', privkey='def', ssl=false)
|
334
|
+
ReCaptcha::Client.new(pubkey, privkey, ssl)
|
335
|
+
end
|
336
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: iGEL-ruby-recaptcha
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Johannes Barre
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-16 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: My almost unchanged fork of ruby-recaptcha
|
17
|
+
email: igel@igels.net
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- lib/recaptcha.rb
|
24
|
+
- lib/ruby-recaptcha.rb
|
25
|
+
- README.textile
|
26
|
+
files:
|
27
|
+
- Manifest
|
28
|
+
- Rakefile
|
29
|
+
- test/test_recaptcha.rb
|
30
|
+
- test/test_helper.rb
|
31
|
+
- script/console
|
32
|
+
- script/generate
|
33
|
+
- script/destroy
|
34
|
+
- lib/recaptcha.rb
|
35
|
+
- lib/ruby-recaptcha.rb
|
36
|
+
- README.textile
|
37
|
+
- ruby-recaptcha.gemspec
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://bitbucket.org/mml/ruby-recaptcha/wiki/Home
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options:
|
42
|
+
- --line-numbers
|
43
|
+
- --inline-source
|
44
|
+
- --title
|
45
|
+
- Ruby-recaptcha
|
46
|
+
- --main
|
47
|
+
- README.textile
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "1.2"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project: ruby-recaptcha
|
65
|
+
rubygems_version: 1.2.0
|
66
|
+
signing_key:
|
67
|
+
specification_version: 2
|
68
|
+
summary: My almost unchanged fork of ruby-recaptcha
|
69
|
+
test_files:
|
70
|
+
- test/test_recaptcha.rb
|
71
|
+
- test/test_helper.rb
|