merb-recaptcha 1.0.3
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/LICENSE +20 -0
- data/README.rdoc +46 -0
- data/Rakefile +77 -0
- data/TODO +1 -0
- data/lib/merb-recaptcha.rb +29 -0
- data/lib/merb-recaptcha/constants.rb +7 -0
- data/lib/merb-recaptcha/controller_mixin.rb +46 -0
- data/lib/merb-recaptcha/exceptions.rb +30 -0
- data/lib/merb-recaptcha/merbtasks.rb +0 -0
- data/lib/merb-recaptcha/view_helpers.rb +117 -0
- data/merb-recaptcha.gemspec +44 -0
- data/spec/fixture/app/controllers/application.rb +2 -0
- data/spec/fixture/app/controllers/exceptions.rb +13 -0
- data/spec/fixture/app/controllers/recaptcha.rb +29 -0
- data/spec/fixture/app/helpers/global_helpers.rb +5 -0
- data/spec/fixture/app/helpers/recaptcha_helpers.rb +4 -0
- data/spec/fixture/app/views/exceptions/not_acceptable.html.erb +63 -0
- data/spec/fixture/app/views/exceptions/not_found.html.erb +47 -0
- data/spec/fixture/app/views/layout/application.html.erb +10 -0
- data/spec/fixture/app/views/recaptcha/ajax.html.erb +2 -0
- data/spec/fixture/app/views/recaptcha/ajax_with_callback.html.erb +2 -0
- data/spec/fixture/app/views/recaptcha/ajax_with_jquery.html.erb +2 -0
- data/spec/fixture/app/views/recaptcha/ajax_with_options.html.erb +2 -0
- data/spec/fixture/app/views/recaptcha/noajax_with_noscript.html.erb +1 -0
- data/spec/fixture/app/views/recaptcha/noajax_with_options.html.erb +1 -0
- data/spec/fixture/app/views/recaptcha/noajax_without_noscript.html.erb +1 -0
- data/spec/recaptcha_ajax_spec.rb +39 -0
- data/spec/recaptcha_ajax_with_callback_spec.rb +35 -0
- data/spec/recaptcha_ajax_with_jquery_spec.rb +39 -0
- data/spec/recaptcha_ajax_with_options_spec.rb +35 -0
- data/spec/recaptcha_noajax_with_noscript_spec.rb +59 -0
- data/spec/recaptcha_noajax_with_options_spec.rb +39 -0
- data/spec/recaptcha_noajax_without_noscript_spec.rb +39 -0
- data/spec/recaptcha_valid_spec.rb +125 -0
- data/spec/spec_helper.rb +46 -0
- metadata +130 -0
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2008 Anton Ageev
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
= merb-recaptcha
|
|
2
|
+
|
|
3
|
+
== About
|
|
4
|
+
|
|
5
|
+
Merb-recaptcha is plugin for Merb web-framework. It provides view and controller helpers for Recaptcha service.
|
|
6
|
+
|
|
7
|
+
== Installation
|
|
8
|
+
|
|
9
|
+
Install gem from github.com:
|
|
10
|
+
gem install antage-merb-recaptcha --source=http://gems.github.com
|
|
11
|
+
|
|
12
|
+
Add following line in <tt>config/dependencies.rb</tt> of your web application:
|
|
13
|
+
dependency "antage-merb-recaptcha", "~> 1.0.0", :require_as => "merb-recaptcha"
|
|
14
|
+
|
|
15
|
+
Sign up at Recaptcha and get public and private keys. Add keys in <tt>config/init.rb</tt>:
|
|
16
|
+
Merb::BootLoader.after_app_loads do
|
|
17
|
+
Merb::Plugins.config[:merb_recaptcha][:public_key] = "... here your public key ..."
|
|
18
|
+
Merb::Plugins.config[:merb_recaptcha][:private_key] = "... here your private key ..."
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
== Usage
|
|
22
|
+
|
|
23
|
+
Just add helper in your form:
|
|
24
|
+
<%= form_for @users, :action => resource(:users), :method => :post do %>
|
|
25
|
+
.....
|
|
26
|
+
<%= recaptcha_tags %>
|
|
27
|
+
<%= submit "Send" %>
|
|
28
|
+
<% end %>
|
|
29
|
+
|
|
30
|
+
And then check captcha in controller:
|
|
31
|
+
class Users < Application
|
|
32
|
+
......
|
|
33
|
+
def create(user)
|
|
34
|
+
@user = User.new(user)
|
|
35
|
+
if (captcha_correct = recaptcha_valid?) && @user.save
|
|
36
|
+
redirect resource(@user)
|
|
37
|
+
else
|
|
38
|
+
unless captcha_correct
|
|
39
|
+
@user.valid?
|
|
40
|
+
@user.errors.add(:general, "Captcha code is incorrect")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
render :new
|
|
44
|
+
end
|
|
45
|
+
......
|
|
46
|
+
end
|
data/Rakefile
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake/gempackagetask'
|
|
3
|
+
require 'rake/rdoctask'
|
|
4
|
+
require 'rake/clean'
|
|
5
|
+
|
|
6
|
+
require 'spec/rake/spectask'
|
|
7
|
+
|
|
8
|
+
require 'merb-core'
|
|
9
|
+
require 'merb-core/tasks/merb'
|
|
10
|
+
|
|
11
|
+
GEM_NAME = "merb-recaptcha"
|
|
12
|
+
GEM_VERSION = "1.0.3"
|
|
13
|
+
EMAIL = "antage@gmail.com"
|
|
14
|
+
HOMEPAGE = "http://github.com/antage/merb-recaptcha/"
|
|
15
|
+
SUMMARY = "Merb plugin that provides helpers for recaptcha.net service"
|
|
16
|
+
|
|
17
|
+
spec = Gem::Specification.new do |s|
|
|
18
|
+
s.rubyforge_project = 'merb-recaptcha'
|
|
19
|
+
s.name = GEM_NAME
|
|
20
|
+
s.version = GEM_VERSION
|
|
21
|
+
s.platform = Gem::Platform::RUBY
|
|
22
|
+
s.authors = ["Anton Ageev", "Michael Johnston"]
|
|
23
|
+
s.has_rdoc = true
|
|
24
|
+
s.extra_rdoc_files = [ "README.rdoc", "LICENSE" ]
|
|
25
|
+
s.rdoc_options << "--main" << "README.rdoc"
|
|
26
|
+
s.summary = SUMMARY
|
|
27
|
+
s.description = s.summary
|
|
28
|
+
s.email = EMAIL
|
|
29
|
+
s.homepage = HOMEPAGE
|
|
30
|
+
s.require_path = 'lib'
|
|
31
|
+
s.files = %w(LICENSE README.rdoc Rakefile TODO merb-recaptcha.gemspec) + Dir["lib/**/*"].select { |f| File.file?(f) }
|
|
32
|
+
s.test_files = %w(spec/spec_helper.rb) + Dir["spec/*_spec.rb"] + Dir["spec/fixture/app/**/*"].select { |f| File.file?(f) }
|
|
33
|
+
|
|
34
|
+
s.add_runtime_dependency "merb-core", ">= 1.0.0"
|
|
35
|
+
s.add_runtime_dependency "builder", "~> 2.0"
|
|
36
|
+
s.add_development_dependency "rspec", ">= 1.1.0"
|
|
37
|
+
s.add_development_dependency "mocha", ">= 0.9.3"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
|
41
|
+
pkg.gem_spec = spec
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
desc "install the plugin as a gem"
|
|
45
|
+
task :install do
|
|
46
|
+
Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
desc "Uninstall the gem"
|
|
50
|
+
task :uninstall do
|
|
51
|
+
Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
desc "Create a gemspec file"
|
|
55
|
+
task :gemspec do
|
|
56
|
+
File.open("#{GEM_NAME}.gemspec", "w") do |file|
|
|
57
|
+
file.puts spec.to_ruby
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
Rake::RDocTask.new do |rdoc|
|
|
62
|
+
files = ["README.rdoc", "LICENSE", "lib/**/*.rb"]
|
|
63
|
+
rdoc.rdoc_files.add(files)
|
|
64
|
+
rdoc.main = "README.rdoc"
|
|
65
|
+
rdoc.title = "merb-recaptcha docs"
|
|
66
|
+
rdoc.rdoc_dir = "doc"
|
|
67
|
+
rdoc.options << "--line-numbers" << "--inline-source"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
|
71
|
+
t.spec_opts << '--format' << 'specdoc' << '--colour'
|
|
72
|
+
t.spec_opts << '--loadby' << 'random'
|
|
73
|
+
t.spec_files = Pathname.glob(ENV['FILES'] || 'spec/**/*_spec.rb')
|
|
74
|
+
t.rcov = false
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
task :default => :spec
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# make sure we're running inside Merb
|
|
2
|
+
if defined?(Merb::Plugins)
|
|
3
|
+
|
|
4
|
+
# Merb gives you a Merb::Plugins.config hash...feel free to put your stuff in your piece of it
|
|
5
|
+
Merb::Plugins.config[:merb_recaptcha] = {
|
|
6
|
+
:public_key => "",
|
|
7
|
+
:private_key => ""
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
Merb::BootLoader.before_app_loads do
|
|
11
|
+
# require code that must be loaded before the application
|
|
12
|
+
require 'merb-recaptcha/constants.rb'
|
|
13
|
+
require 'merb-recaptcha/view_helpers.rb'
|
|
14
|
+
require 'merb-recaptcha/exceptions.rb'
|
|
15
|
+
require 'merb-recaptcha/controller_mixin.rb'
|
|
16
|
+
module Merb::GlobalHelpers # :nodoc:
|
|
17
|
+
include Merb::Helpers::Recaptcha
|
|
18
|
+
end
|
|
19
|
+
class Merb::Controller # :nodoc:
|
|
20
|
+
include Merb::RecaptchaMixin
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Merb::BootLoader.after_app_loads do
|
|
25
|
+
# code that can be required after the application loads
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Merb::Plugins.add_rakefiles "merb-recaptcha/merbtasks"
|
|
29
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
|
|
3
|
+
module Merb # :nodoc:
|
|
4
|
+
module RecaptchaMixin
|
|
5
|
+
|
|
6
|
+
# This method checks challenge and response data via Recaptcha API server.
|
|
7
|
+
# * It will return true, if filled captcha response is correct.
|
|
8
|
+
# * It will return false, if captcha is incorrect.
|
|
9
|
+
# * It will raise exception, if Recaptcha API server returns error.
|
|
10
|
+
#
|
|
11
|
+
def recaptcha_valid?
|
|
12
|
+
return true if (Merb.testing? && !Merb::RecaptchaMixin.const_defined?(:DO_NOT_IGNORE_RECAPTCHA_IN_TESTING_ENV))
|
|
13
|
+
begin
|
|
14
|
+
response = Net::HTTP.post_form(URI.parse("#{Merb::Recaptcha::API_VERIFY_SERVER}/verify"), {
|
|
15
|
+
:privatekey => Merb::Plugins.config[:merb_recaptcha][:private_key],
|
|
16
|
+
:remoteip => request.remote_ip,
|
|
17
|
+
:challenge => params[:recaptcha_challenge_field],
|
|
18
|
+
:response => params[:recaptcha_response_field]
|
|
19
|
+
})
|
|
20
|
+
rescue Exception => e
|
|
21
|
+
if Merb.env?(:production) || ENV['OFFLINE']
|
|
22
|
+
Merb.logger.error("when trying to connect to recaptcha, got #{e.message}")
|
|
23
|
+
return true;
|
|
24
|
+
else
|
|
25
|
+
raise
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
answer, error = response.body.split.map { |s| s.chomp }
|
|
29
|
+
if answer == "true"
|
|
30
|
+
true
|
|
31
|
+
else
|
|
32
|
+
Merb.logger.fatal("recaptcha error: #{error} for #{request.remote_ip}")
|
|
33
|
+
case error
|
|
34
|
+
when "incorrect-captcha-sol" then false
|
|
35
|
+
when "invalid-site-public-key" then raise Merb::Recaptcha::InvalidSitePublicKey
|
|
36
|
+
when "invalid-site-private-key" then raise Merb::Recaptcha::InvalidSitePrivateKey
|
|
37
|
+
when "invalid-request-cookie" then raise Merb::Recaptcha::InvalidRequestCookie
|
|
38
|
+
when "verify-params-incorrect" then raise Merb::Recaptcha::VerifyParamsIncorrect
|
|
39
|
+
when "invalid-referrer" then raise Merb::Recaptcha::InvalidReferrer
|
|
40
|
+
else
|
|
41
|
+
raise Merb::Recaptcha::GenericError
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Merb # :nodoc:
|
|
2
|
+
module Recaptcha
|
|
3
|
+
class GenericError < RuntimeError; end
|
|
4
|
+
|
|
5
|
+
# We weren't able to verify the public key.
|
|
6
|
+
# Possible solutions:
|
|
7
|
+
#
|
|
8
|
+
# * Did you swap the public and private key? It is important to use the correct one
|
|
9
|
+
# * Did you make sure to copy the entire key, with all hyphens and underscores, but without any spaces? The key should be exactly 40 letters long.
|
|
10
|
+
#
|
|
11
|
+
class InvalidSitePublicKey < GenericError; end
|
|
12
|
+
|
|
13
|
+
# We weren't able to verify the private key.
|
|
14
|
+
# Possible solutions:
|
|
15
|
+
#
|
|
16
|
+
# * Did you swap the public and private key? It is important to use the correct one
|
|
17
|
+
# * Did you make sure to copy the entire key, with all hyphens and underscores, but without any spaces? The key should be exactly 40 letters long.
|
|
18
|
+
#
|
|
19
|
+
class InvalidSitePrivateKey < GenericError; end
|
|
20
|
+
|
|
21
|
+
# The challenge parameter of the verify script was incorrect.
|
|
22
|
+
class InvalidRequestCookie < GenericError; end
|
|
23
|
+
|
|
24
|
+
# The parameters to /verify were incorrect, make sure you are passing all the required parameters.
|
|
25
|
+
class VerifyParamsIncorrect < GenericError; end
|
|
26
|
+
|
|
27
|
+
# reCAPTCHA API keys are tied to a specific domain name for security reasons.
|
|
28
|
+
class InvalidReferrer < GenericError; end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
require 'builder'
|
|
2
|
+
|
|
3
|
+
module Merb # :nodoc:
|
|
4
|
+
module Helpers # :nodoc:
|
|
5
|
+
module Recaptcha
|
|
6
|
+
|
|
7
|
+
# Display recaptcha widget in various ways.
|
|
8
|
+
#
|
|
9
|
+
# * Display in-place:
|
|
10
|
+
# <%= recaptcha_tags :ajax => false, :noscript => false %>
|
|
11
|
+
#
|
|
12
|
+
# * Display in-place with <noscript></noscript> block:
|
|
13
|
+
# <%= recaptcha_tags :ajax => false, :noscript => true, :iframe_height => 100, :iframe_width => 100 %>
|
|
14
|
+
#
|
|
15
|
+
# * Dynamically create Recaptcha widget:
|
|
16
|
+
# <%= recaptcha_tags :ajax => true, :element_id => "recaptcha_place" %>
|
|
17
|
+
# <div id="recaptcha_place"></div>
|
|
18
|
+
# The above code bind javascript code on onload event:
|
|
19
|
+
# <script type="text/javascript">
|
|
20
|
+
# ....
|
|
21
|
+
# window.onload = function() { Recaptcha.create(....); }
|
|
22
|
+
# ....
|
|
23
|
+
# </script>
|
|
24
|
+
# If you use jQuery, you could use special value for :ajax parameter:
|
|
25
|
+
# <%= recaptcha_tags :ajax => :jquery %>
|
|
26
|
+
# <div id="recpatcha"></div>
|
|
27
|
+
# This code generates following:
|
|
28
|
+
# <script type="text/javascript">
|
|
29
|
+
# ....
|
|
30
|
+
# $(document).ready(function() { Recaptcha.create(....); });
|
|
31
|
+
# ....
|
|
32
|
+
# </script>
|
|
33
|
+
# You can specified callback function that will be invoked after widget has been created:
|
|
34
|
+
# <%= recaptcha_tags :ajax => true, :callback => "Recaptcha.focus_response_field" %>
|
|
35
|
+
# <div id="recaptcha"></div>
|
|
36
|
+
# This code will set focus on response field of created widget.
|
|
37
|
+
#
|
|
38
|
+
# For both displaying ways, you can customize widget:
|
|
39
|
+
# <%= recaptcha_tags :theme => "clean", :tabindex => 2 %>
|
|
40
|
+
# More detailed description of customizing options is at http://recaptcha.net/apidocs/captcha/client.html
|
|
41
|
+
#
|
|
42
|
+
# Default values of options:
|
|
43
|
+
# * :ajax => false
|
|
44
|
+
# * :element_id => "recaptcha"
|
|
45
|
+
# * :callback => nil
|
|
46
|
+
# * :noscript => false
|
|
47
|
+
# * :iframe_height => 300
|
|
48
|
+
# * :iframe_width => 500
|
|
49
|
+
#
|
|
50
|
+
def recaptcha_tags(options = {})
|
|
51
|
+
public_key = Merb::Plugins.config[:merb_recaptcha][:public_key]
|
|
52
|
+
|
|
53
|
+
ajax = options.delete(:ajax) || false # boolean or :jquery
|
|
54
|
+
element_id = options.delete(:element_id) || "recaptcha" # string, html element id, only if ajax == true
|
|
55
|
+
callback = options.delete(:callback) # string, javascript function name, only if ajax == true
|
|
56
|
+
noscript = options.delete(:noscript) || false # boolean
|
|
57
|
+
iframe_height = options.delete(:iframe_height) || 300 # integer, only if noscript == true
|
|
58
|
+
iframe_width = options.delete(:iframe_width) || 500 # integer, only if noscript == true
|
|
59
|
+
|
|
60
|
+
api_url = if request.ssl?
|
|
61
|
+
Merb::Recaptcha::API_SECURE_SERVER
|
|
62
|
+
else
|
|
63
|
+
Merb::Recaptcha::API_SERVER
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
result = ""
|
|
67
|
+
xhtml = Builder::XmlMarkup.new(:target => result, :indent => 2)
|
|
68
|
+
if ajax
|
|
69
|
+
xhtml.script(:type => "text/javascript", :src => "#{api_url}/js/recaptcha_ajax.js") {}
|
|
70
|
+
xhtml.script(:type => "text/javascript") do |js|
|
|
71
|
+
options_and_callback = callback.nil? ? options : options.merge(:callback => callback)
|
|
72
|
+
js << "//<![CDATA[\n"
|
|
73
|
+
js << "var options = #{hash_to_json(options_and_callback)};\n"
|
|
74
|
+
if ajax == :jquery
|
|
75
|
+
js << "$(document).ready(function() { Recaptcha.create('#{public_key}', document.getElementById('#{element_id}'), options); });\n"
|
|
76
|
+
else
|
|
77
|
+
js << "window.onload = function() { Recaptcha.create('#{public_key}', document.getElementById('#{element_id}'), options); };\n"
|
|
78
|
+
end
|
|
79
|
+
js << "//]]>\n"
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
unless options.empty?
|
|
83
|
+
xhtml.script(:type => "text/javascript") do |js|
|
|
84
|
+
js << "//<![CDATA[\n"
|
|
85
|
+
js << "var RecaptchaOptions = #{hash_to_json(options)};\n"
|
|
86
|
+
js << "//]]>\n"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
xhtml.script(:type => "text/javascript", :src => "#{api_url}/challenge?k=#{public_key}") {}
|
|
90
|
+
if noscript
|
|
91
|
+
xhtml.noscript do
|
|
92
|
+
xhtml.iframe(:src => "#{api_url}/noscript?k=#{public_key}", :height => iframe_height, :width => iframe_width, :frameborder => 0) {}
|
|
93
|
+
xhtml.br
|
|
94
|
+
xhtml.textarea(:name => "recaptcha_challenge_field", :rows => 3, :cols => 40) {}
|
|
95
|
+
xhtml.input :name => "recaptcha_response_field", :type => "hidden", :value => "manual_challenge"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
result
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
def hash_to_json(hash)
|
|
105
|
+
result = "{"
|
|
106
|
+
result << hash.map do |k, v|
|
|
107
|
+
if ! v.is_a?(String) || k.to_s == "callback"
|
|
108
|
+
"\"#{k}\": #{v}"
|
|
109
|
+
else
|
|
110
|
+
"\"#{k}\": \"#{v}\""
|
|
111
|
+
end
|
|
112
|
+
end.join(", ")
|
|
113
|
+
result << "}"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{merb-recaptcha}
|
|
5
|
+
s.version = "1.0.3"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Anton Ageev", "Michael Johnston"]
|
|
9
|
+
s.date = %q{2009-05-29}
|
|
10
|
+
s.description = %q{Merb plugin that provides helpers for recaptcha.net service}
|
|
11
|
+
s.email = %q{antage@gmail.com}
|
|
12
|
+
s.extra_rdoc_files = ["README.rdoc", "LICENSE"]
|
|
13
|
+
s.files = ["LICENSE", "README.rdoc", "Rakefile", "TODO", "merb-recaptcha.gemspec", "lib/merb-recaptcha/merbtasks.rb", "lib/merb-recaptcha/constants.rb", "lib/merb-recaptcha/exceptions.rb", "lib/merb-recaptcha/view_helpers.rb", "lib/merb-recaptcha/controller_mixin.rb", "lib/merb-recaptcha.rb", "spec/spec_helper.rb", "spec/recaptcha_ajax_with_callback_spec.rb", "spec/recaptcha_noajax_with_noscript_spec.rb", "spec/recaptcha_noajax_with_options_spec.rb", "spec/recaptcha_ajax_spec.rb", "spec/recaptcha_ajax_with_jquery_spec.rb", "spec/recaptcha_ajax_with_options_spec.rb", "spec/recaptcha_noajax_without_noscript_spec.rb", "spec/recaptcha_valid_spec.rb", "spec/fixture/app/views/layout/application.html.erb", "spec/fixture/app/views/recaptcha/ajax_with_callback.html.erb", "spec/fixture/app/views/recaptcha/noajax_with_noscript.html.erb", "spec/fixture/app/views/recaptcha/ajax.html.erb", "spec/fixture/app/views/recaptcha/ajax_with_jquery.html.erb", "spec/fixture/app/views/recaptcha/noajax_with_options.html.erb", "spec/fixture/app/views/recaptcha/noajax_without_noscript.html.erb", "spec/fixture/app/views/recaptcha/ajax_with_options.html.erb", "spec/fixture/app/views/exceptions/not_acceptable.html.erb", "spec/fixture/app/views/exceptions/not_found.html.erb", "spec/fixture/app/controllers/exceptions.rb", "spec/fixture/app/controllers/application.rb", "spec/fixture/app/controllers/recaptcha.rb", "spec/fixture/app/helpers/recaptcha_helpers.rb", "spec/fixture/app/helpers/global_helpers.rb"]
|
|
14
|
+
s.has_rdoc = true
|
|
15
|
+
s.homepage = %q{http://github.com/antage/merb-recaptcha/}
|
|
16
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
|
17
|
+
s.require_paths = ["lib"]
|
|
18
|
+
s.rubyforge_project = %q{merb-recaptcha}
|
|
19
|
+
s.rubygems_version = %q{1.3.1}
|
|
20
|
+
s.summary = %q{Merb plugin that provides helpers for recaptcha.net service}
|
|
21
|
+
s.test_files = ["spec/spec_helper.rb", "spec/recaptcha_ajax_with_callback_spec.rb", "spec/recaptcha_noajax_with_noscript_spec.rb", "spec/recaptcha_noajax_with_options_spec.rb", "spec/recaptcha_ajax_spec.rb", "spec/recaptcha_ajax_with_jquery_spec.rb", "spec/recaptcha_ajax_with_options_spec.rb", "spec/recaptcha_noajax_without_noscript_spec.rb", "spec/recaptcha_valid_spec.rb", "spec/fixture/app/views/layout/application.html.erb", "spec/fixture/app/views/recaptcha/ajax_with_callback.html.erb", "spec/fixture/app/views/recaptcha/noajax_with_noscript.html.erb", "spec/fixture/app/views/recaptcha/ajax.html.erb", "spec/fixture/app/views/recaptcha/ajax_with_jquery.html.erb", "spec/fixture/app/views/recaptcha/noajax_with_options.html.erb", "spec/fixture/app/views/recaptcha/noajax_without_noscript.html.erb", "spec/fixture/app/views/recaptcha/ajax_with_options.html.erb", "spec/fixture/app/views/exceptions/not_acceptable.html.erb", "spec/fixture/app/views/exceptions/not_found.html.erb", "spec/fixture/app/controllers/exceptions.rb", "spec/fixture/app/controllers/application.rb", "spec/fixture/app/controllers/recaptcha.rb", "spec/fixture/app/helpers/recaptcha_helpers.rb", "spec/fixture/app/helpers/global_helpers.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
|
+
s.add_runtime_dependency(%q<merb-core>, [">= 1.0.0"])
|
|
29
|
+
s.add_runtime_dependency(%q<builder>, ["~> 2.0"])
|
|
30
|
+
s.add_development_dependency(%q<rspec>, [">= 1.1.0"])
|
|
31
|
+
s.add_development_dependency(%q<mocha>, [">= 0.9.3"])
|
|
32
|
+
else
|
|
33
|
+
s.add_dependency(%q<merb-core>, [">= 1.0.0"])
|
|
34
|
+
s.add_dependency(%q<builder>, ["~> 2.0"])
|
|
35
|
+
s.add_dependency(%q<rspec>, [">= 1.1.0"])
|
|
36
|
+
s.add_dependency(%q<mocha>, [">= 0.9.3"])
|
|
37
|
+
end
|
|
38
|
+
else
|
|
39
|
+
s.add_dependency(%q<merb-core>, [">= 1.0.0"])
|
|
40
|
+
s.add_dependency(%q<builder>, ["~> 2.0"])
|
|
41
|
+
s.add_dependency(%q<rspec>, [">= 1.1.0"])
|
|
42
|
+
s.add_dependency(%q<mocha>, [">= 0.9.3"])
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
class Recaptcha < Application
|
|
2
|
+
def ajax
|
|
3
|
+
render
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def ajax_with_jquery
|
|
7
|
+
render
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def ajax_with_callback
|
|
11
|
+
render
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def ajax_with_options
|
|
15
|
+
render
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def noajax_without_noscript
|
|
19
|
+
render
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def noajax_with_noscript
|
|
23
|
+
render
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def noajax_with_options
|
|
27
|
+
render
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<div id="container">
|
|
2
|
+
<div id="header-container">
|
|
3
|
+
<img src="/images/merb.jpg" />
|
|
4
|
+
<!-- <h1>Mongrel + Erb</h1> -->
|
|
5
|
+
<h2>pocket rocket web framework</h2>
|
|
6
|
+
<hr />
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div id="left-container">
|
|
10
|
+
<h3>Exception:</h3>
|
|
11
|
+
<p><%= request.exceptions.first.message %></p>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<div id="main-container">
|
|
15
|
+
<h3>Why am I seeing this page?</h3>
|
|
16
|
+
<p>Merb couldn't find an appropriate content_type to return,
|
|
17
|
+
based on what you said was available via provides() and
|
|
18
|
+
what the client requested.</p>
|
|
19
|
+
|
|
20
|
+
<h3>How to add a mime-type</h3>
|
|
21
|
+
<pre><code>
|
|
22
|
+
Merb.add_mime_type :pdf, :to_pdf, %w[application/pdf], "Content-Encoding" => "gzip"
|
|
23
|
+
</code></pre>
|
|
24
|
+
<h3>What this means is:</h3>
|
|
25
|
+
<ul>
|
|
26
|
+
<li>Add a mime-type for :pdf</li>
|
|
27
|
+
<li>Register the method for converting objects to PDF as <code>#to_pdf</code>.</li>
|
|
28
|
+
<li>Register the incoming mime-type "Accept" header as <code>application/pdf</code>.</li>
|
|
29
|
+
<li>Specify a new header for PDF types so it will set <code>Content-Encoding</code> to gzip.</li>
|
|
30
|
+
</ul>
|
|
31
|
+
|
|
32
|
+
<h3>You can then do:</h3>
|
|
33
|
+
<pre><code>
|
|
34
|
+
class Foo < Application
|
|
35
|
+
provides :pdf
|
|
36
|
+
end
|
|
37
|
+
</code></pre>
|
|
38
|
+
|
|
39
|
+
<h3>Where can I find help?</h3>
|
|
40
|
+
<p>If you have any questions or if you can't figure something out, please take a
|
|
41
|
+
look at our <a href="http://merbivore.com/"> project page</a>,
|
|
42
|
+
feel free to come chat at irc.freenode.net, channel #merb,
|
|
43
|
+
or post to <a href="http://groups.google.com/group/merb">merb mailing list</a>
|
|
44
|
+
on Google Groups.</p>
|
|
45
|
+
|
|
46
|
+
<h3>What if I've found a bug?</h3>
|
|
47
|
+
<p>If you want to file a bug or make your own contribution to Merb,
|
|
48
|
+
feel free to register and create a ticket at our
|
|
49
|
+
<a href="http://merb.lighthouseapp.com/">project development page</a>
|
|
50
|
+
on Lighthouse.</p>
|
|
51
|
+
|
|
52
|
+
<h3>How do I edit this page?</h3>
|
|
53
|
+
<p>You can change what people see when this happens by editing <tt>app/views/exceptions/not_acceptable.html.erb</tt>.</p>
|
|
54
|
+
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div id="footer-container">
|
|
58
|
+
<hr />
|
|
59
|
+
<div class="left"></div>
|
|
60
|
+
<div class="right">© 2008 the merb dev team</div>
|
|
61
|
+
<p> </p>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<div id="container">
|
|
2
|
+
<div id="header-container">
|
|
3
|
+
<img src="/images/merb.jpg" />
|
|
4
|
+
<!-- <h1>Mongrel + Erb</h1> -->
|
|
5
|
+
<h2>pocket rocket web framework</h2>
|
|
6
|
+
<hr />
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div id="left-container">
|
|
10
|
+
<h3>Exception:</h3>
|
|
11
|
+
<p><%= request.exceptions.first.message %></p>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<div id="main-container">
|
|
15
|
+
<h3>Welcome to Merb!</h3>
|
|
16
|
+
<p>Merb is a light-weight MVC framework written in Ruby. We hope you enjoy it.</p>
|
|
17
|
+
|
|
18
|
+
<h3>Where can I find help?</h3>
|
|
19
|
+
<p>If you have any questions or if you can't figure something out, please take a
|
|
20
|
+
look at our <a href="http://merbivore.com/"> project page</a>,
|
|
21
|
+
feel free to come chat at irc.freenode.net, channel #merb,
|
|
22
|
+
or post to <a href="http://groups.google.com/group/merb">merb mailing list</a>
|
|
23
|
+
on Google Groups.</p>
|
|
24
|
+
|
|
25
|
+
<h3>What if I've found a bug?</h3>
|
|
26
|
+
<p>If you want to file a bug or make your own contribution to Merb,
|
|
27
|
+
feel free to register and create a ticket at our
|
|
28
|
+
<a href="http://merb.lighthouseapp.com/">project development page</a>
|
|
29
|
+
on Lighthouse.</p>
|
|
30
|
+
|
|
31
|
+
<h3>How do I edit this page?</h3>
|
|
32
|
+
<p>You're seeing this page because you need to edit the following files:
|
|
33
|
+
<ul>
|
|
34
|
+
<li>config/router.rb <strong><em>(recommended)</em></strong></li>
|
|
35
|
+
<li>app/views/exceptions/not_found.html.erb <strong><em>(recommended)</em></strong></li>
|
|
36
|
+
<li>app/views/layout/application.html.erb <strong><em>(change this layout)</em></strong></li>
|
|
37
|
+
</ul>
|
|
38
|
+
</p>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div id="footer-container">
|
|
42
|
+
<hr />
|
|
43
|
+
<div class="left"></div>
|
|
44
|
+
<div class="right">© 2008 the merb dev team</div>
|
|
45
|
+
<p> </p>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
|
|
3
|
+
<head>
|
|
4
|
+
<title>Fresh Merb App</title>
|
|
5
|
+
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
|
6
|
+
</head>
|
|
7
|
+
<body>
|
|
8
|
+
<%= catch_content :for_layout %>
|
|
9
|
+
</body>
|
|
10
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= recaptcha_tags :ajax => false, :noscript => true, :iframe_height => 250, :iframe_width => 250 %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= recaptcha_tags :ajax => false, :noscript => false, :theme => "clean", :tabindex => 2 %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= recaptcha_tags :ajax => false, :noscript => false %>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "Recaptcha#ajax" do
|
|
4
|
+
describe "HTTP" do
|
|
5
|
+
before(:each) do
|
|
6
|
+
@response = dispatch_to(Recaptcha, "ajax")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should load script from api url" do
|
|
10
|
+
@response.should have_xpath("//script[@src='http://api.recaptcha.net/js/recaptcha_ajax.js']")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should invoke Recaptcha.create using onload event" do
|
|
14
|
+
@response.should have_xpath("//script[contains(., 'window.onload = function() { Recaptcha.create')]")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should send element_id ('recaptcha_without_callback')" do
|
|
18
|
+
@response.should have_xpath("//script[contains(., 'Recaptcha.create') and contains(., \"getElementById('recaptcha_without_callback')\")]")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should create empty options array" do
|
|
22
|
+
@response.should have_xpath("//script[contains(., 'Recaptcha.create') and contains(., 'var options = {};')]")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it_should_behave_like "ajax recaptcha"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "HTTPS" do
|
|
29
|
+
before(:each) do
|
|
30
|
+
@response = dispatch_to(Recaptcha, "ajax", {}, { "HTTPS" => "on" })
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should load script from secure api url" do
|
|
34
|
+
@response.should have_xpath("//script[@src='https://api-secure.recaptcha.net/js/recaptcha_ajax.js']")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it_should_behave_like "ajax recaptcha"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "Recaptcha#ajax_with_callback" do
|
|
4
|
+
describe "HTTP" do
|
|
5
|
+
before(:each) do
|
|
6
|
+
@response = dispatch_to(Recaptcha, "ajax_with_callback")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should load script from api url" do
|
|
10
|
+
@response.should have_xpath("//script[@src='http://api.recaptcha.net/js/recaptcha_ajax.js']")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should send element_id ('recaptcha_with_callback')" do
|
|
14
|
+
@response.should have_xpath("//script[contains(., 'Recaptcha.create') and contains(., \"getElementById('recaptcha_with_callback')\")]")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should create options array containing callback value ('test_callback')" do
|
|
18
|
+
@response.should have_xpath("//script[contains(., 'Recaptcha.create') and contains(., 'var options = {\"callback\": test_callback};')]")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it_should_behave_like "ajax recaptcha"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "HTTPS" do
|
|
25
|
+
before(:each) do
|
|
26
|
+
@response = dispatch_to(Recaptcha, "ajax_with_callback", {}, { "HTTPS" => "on" })
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should load script from secure api url" do
|
|
30
|
+
@response.should have_xpath("//script[@src='https://api-secure.recaptcha.net/js/recaptcha_ajax.js']")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it_should_behave_like "ajax recaptcha"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "Recaptcha#ajax_with_jquery" do
|
|
4
|
+
describe "HTTP" do
|
|
5
|
+
before(:each) do
|
|
6
|
+
@response = dispatch_to(Recaptcha, "ajax_with_jquery")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should load script from api url" do
|
|
10
|
+
@response.should have_xpath("//script[@src='http://api.recaptcha.net/js/recaptcha_ajax.js']")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should invoke Recaptcha.create using onload event" do
|
|
14
|
+
@response.should have_xpath("//script[contains(., '$(document).ready(function() { Recaptcha.create')]")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should send element_id ('recaptcha_without_callback')" do
|
|
18
|
+
@response.should have_xpath("//script[contains(., 'Recaptcha.create') and contains(., \"getElementById('recaptcha_without_callback')\")]")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should create empty options array" do
|
|
22
|
+
@response.should have_xpath("//script[contains(., 'Recaptcha.create') and contains(., 'var options = {};')]")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it_should_behave_like "ajax recaptcha"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "HTTPS" do
|
|
29
|
+
before(:each) do
|
|
30
|
+
@response = dispatch_to(Recaptcha, "ajax_with_jquery", {}, { "HTTPS" => "on" })
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should load script from secure api url" do
|
|
34
|
+
@response.should have_xpath("//script[@src='https://api-secure.recaptcha.net/js/recaptcha_ajax.js']")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it_should_behave_like "ajax recaptcha"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "Recaptcha#ajax_with_options" do
|
|
4
|
+
describe "HTTP" do
|
|
5
|
+
before(:each) do
|
|
6
|
+
@response = dispatch_to(Recaptcha, "ajax_with_options")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should load script from api url" do
|
|
10
|
+
@response.should have_xpath("//script[@src='http://api.recaptcha.net/js/recaptcha_ajax.js']")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should send element_id ('recaptcha_without_callback')" do
|
|
14
|
+
@response.should have_xpath("//script[contains(., 'Recaptcha.create') and contains(., \"getElementById('recaptcha_without_callback')\")]")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should create options array containing custom options (theme = 'clean', tabindex = 2)" do
|
|
18
|
+
@response.should have_xpath("//script[contains(., 'Recaptcha.create') and (contains(., 'var options = {\"theme\": \"clean\", \"tabindex\": 2};') or contains(., 'var options = {\"tabindex\": 2, \"theme\": \"clean\"};'))]")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it_should_behave_like "ajax recaptcha"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "HTTPS" do
|
|
25
|
+
before(:each) do
|
|
26
|
+
@response = dispatch_to(Recaptcha, "ajax_with_options", {}, { "HTTPS" => "on" })
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should load script from secure api url" do
|
|
30
|
+
@response.should have_xpath("//script[@src='https://api-secure.recaptcha.net/js/recaptcha_ajax.js']")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it_should_behave_like "ajax recaptcha"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "Recaptcha#noajax_with_noscript" do
|
|
4
|
+
describe "HTTP" do
|
|
5
|
+
before(:each) do
|
|
6
|
+
@response = dispatch_to(Recaptcha, "noajax_with_noscript")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should load script from api url" do
|
|
10
|
+
@response.should have_xpath("//script[@src='http://api.recaptcha.net/challenge?k=#{Merb::Plugins.config[:merb_recaptcha][:public_key]}']")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should not send private key to anything" do
|
|
14
|
+
@response.should_not have_xpath("//*[contains(., '#{Merb::Plugins.config[:merb_recaptcha][:private_key]}')]")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should not have RecaptchaOptions array initialization" do
|
|
18
|
+
@response.should_not have_xpath("//script[contains(., 'var RecaptchaOptions')]")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should have noscript element" do
|
|
22
|
+
@response.should have_xpath("//noscript")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should have iframe in noscript element" do
|
|
26
|
+
@response.should have_xpath("//noscript/iframe")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should have iframe with specified height and width (250x250)" do
|
|
30
|
+
@response.should have_xpath("//noscript/iframe[@height=250 and @width=250]")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should have br element in noscript element" do
|
|
34
|
+
@response.should have_xpath("//noscript/br")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should have textarea in noscript element" do
|
|
38
|
+
@response.should have_xpath("//noscript/textarea[@name='recaptcha_challenge_field']")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should have hidden input element in noscript element" do
|
|
42
|
+
@response.should have_xpath("//noscript/input[@name='recaptcha_response_field' and @type='hidden' and @value='manual_challenge']")
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe "HTTPS" do
|
|
47
|
+
before(:each) do
|
|
48
|
+
@response = dispatch_to(Recaptcha, "noajax_with_noscript", {}, { "HTTPS" => "on" })
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should load script from secure api url" do
|
|
52
|
+
@response.should have_xpath("//script[@src='https://api-secure.recaptcha.net/challenge?k=#{Merb::Plugins.config[:merb_recaptcha][:public_key]}']")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should not send private key to anything" do
|
|
56
|
+
@response.should_not have_xpath("//*[contains(., '#{Merb::Plugins.config[:merb_recaptcha][:private_key]}')]")
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "Recaptcha#noajax_with_options" do
|
|
4
|
+
describe "HTTP" do
|
|
5
|
+
before(:each) do
|
|
6
|
+
@response = dispatch_to(Recaptcha, "noajax_with_options")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should load script from api url" do
|
|
10
|
+
@response.should have_xpath("//script[@src='http://api.recaptcha.net/challenge?k=#{Merb::Plugins.config[:merb_recaptcha][:public_key]}']")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should not send private key to anything" do
|
|
14
|
+
@response.should_not have_xpath("//*[contains(., '#{Merb::Plugins.config[:merb_recaptcha][:private_key]}')]")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should not have noscript element" do
|
|
18
|
+
@response.should_not have_xpath("//noscript")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should have RecaptchaOptions array intialization (theme = 'clean', tabindex = 2)" do
|
|
22
|
+
@response.should have_xpath("//script[contains(., 'var RecaptchaOptions = {\"theme\": \"clean\", \"tabindex\": 2};') or contains(., 'var RecaptchaOptions = {\"tabindex\": 2, \"theme\": \"clean\"};')]")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "HTTPS" do
|
|
27
|
+
before(:each) do
|
|
28
|
+
@response = dispatch_to(Recaptcha, "noajax_with_options", {}, { "HTTPS" => "on" })
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should load script from secure api url" do
|
|
32
|
+
@response.should have_xpath("//script[@src='https://api-secure.recaptcha.net/challenge?k=#{Merb::Plugins.config[:merb_recaptcha][:public_key]}']")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "should not send private key to anything" do
|
|
36
|
+
@response.should_not have_xpath("//*[contains(., '#{Merb::Plugins.config[:merb_recaptcha][:private_key]}')]")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "Recaptcha#noajax_without_noscript" do
|
|
4
|
+
describe "HTTP" do
|
|
5
|
+
before(:each) do
|
|
6
|
+
@response = dispatch_to(Recaptcha, "noajax_without_noscript")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should load script from api url" do
|
|
10
|
+
@response.should have_xpath("//script[@src='http://api.recaptcha.net/challenge?k=#{Merb::Plugins.config[:merb_recaptcha][:public_key]}']")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should not send private key to anything" do
|
|
14
|
+
@response.should_not have_xpath("//*[contains(., '#{Merb::Plugins.config[:merb_recaptcha][:private_key]}')]")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should not have noscript element" do
|
|
18
|
+
@response.should_not have_xpath("//noscript")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should not have RecaptchaOptions array initialization" do
|
|
22
|
+
@response.should_not have_xpath("//script[contains(., 'var RecaptchaOptions')]")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "HTTPS" do
|
|
27
|
+
before(:each) do
|
|
28
|
+
@response = dispatch_to(Recaptcha, "noajax_without_noscript", {}, { "HTTPS" => "on" })
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should load script from secure api url" do
|
|
32
|
+
@response.should have_xpath("//script[@src='https://api-secure.recaptcha.net/challenge?k=#{Merb::Plugins.config[:merb_recaptcha][:public_key]}']")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "should not send private key to anything" do
|
|
36
|
+
@response.should_not have_xpath("//*[contains(., '#{Merb::Plugins.config[:merb_recaptcha][:private_key]}')]")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
|
2
|
+
|
|
3
|
+
class FakeController < Merb::Controller
|
|
4
|
+
def check_recaptcha
|
|
5
|
+
return recaptcha_valid?.to_s
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe "FakeController#check_recaptcha" do
|
|
10
|
+
def do_request(ssl = false)
|
|
11
|
+
@response = dispatch_to(FakeController, :check_recaptcha, { :recaptcha_challenge_field => "blabla", :recaptcha_response_field => "blabla" }, { "HTTPS" => ssl ? "on" : "off" })
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def stub_response(body)
|
|
15
|
+
Net::HTTP.stubs(:post_form).returns stub("Net::HTTPResponse", :body => body)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "with non-SSL request" do
|
|
19
|
+
it "should use non-ssl API server" do
|
|
20
|
+
cond = proc { |*args| args.first.is_a?(URI::HTTP) && args.first.scheme == "http" && args.first.host == "api-verify.recaptcha.net" }
|
|
21
|
+
Net::HTTP.expects(:post_form).with(&cond).returns(stub("Net::HTTPResponse", :body => "true"))
|
|
22
|
+
do_request(false)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "with SSL request" do
|
|
27
|
+
it "should use non-ssl API server" do
|
|
28
|
+
cond = proc { |*args| args.first.is_a?(URI::HTTP) && args.first.scheme == "http" && args.first.host == "api-verify.recaptcha.net" }
|
|
29
|
+
Net::HTTP.expects(:post_form).with(&cond).returns(stub("Net::HTTPResponse", :body => "true"))
|
|
30
|
+
do_request(true)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "with correct response" do
|
|
35
|
+
before(:each) do
|
|
36
|
+
stub_response("true\n")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should render 'true'" do
|
|
40
|
+
do_request
|
|
41
|
+
@response.should have_selector("*:contains('true')")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should not raise any exception" do
|
|
45
|
+
lambda { do_request }.should_not raise_error
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe "with incorrect response" do
|
|
50
|
+
before(:each) do
|
|
51
|
+
stub_response("false\nincorrect-captcha-sol\n")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should render 'false'" do
|
|
55
|
+
do_request
|
|
56
|
+
@response.should have_selector("*:contains('false')")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should not raise any exception" do
|
|
60
|
+
lambda { do_request }.should_not raise_error
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "with incorrect public key" do
|
|
65
|
+
before(:each) do
|
|
66
|
+
stub_response("false\ninvalid-site-public-key\n")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "should raise Merb::Recaptcha::InvalidSitePublicKey" do
|
|
70
|
+
lambda { do_request }.should raise_error(Merb::Recaptcha::InvalidSitePublicKey)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe "with incorrect private key" do
|
|
75
|
+
before(:each) do
|
|
76
|
+
stub_response("false\ninvalid-site-private-key\n")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "should raise Merb::Recaptcha::InvalidSitePrivateKey" do
|
|
80
|
+
lambda { do_request }.should raise_error(Merb::Recaptcha::InvalidSitePrivateKey)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe "with invalid request cookie" do
|
|
85
|
+
before(:each) do
|
|
86
|
+
stub_response("false\ninvalid-request-cookie\n")
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "should raise Merb::Recaptcha::InvalidRequestCookie" do
|
|
90
|
+
lambda { do_request }.should raise_error(Merb::Recaptcha::InvalidRequestCookie)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
describe "with verify parameters incorrect" do
|
|
95
|
+
before(:each) do
|
|
96
|
+
stub_response("false\nverify-params-incorrect\n")
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "should raise Merb::Recaptcha::VerifyParamsIncorrect" do
|
|
100
|
+
lambda { do_request }.should raise_error(Merb::Recaptcha::VerifyParamsIncorrect)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe "with invalid referrer" do
|
|
105
|
+
before(:each) do
|
|
106
|
+
stub_response("false\ninvalid-referrer\n")
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "should raise Merb::Recaptcha::IvalidReferrer" do
|
|
110
|
+
lambda { do_request }.should raise_error(Merb::Recaptcha::InvalidReferrer)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe "when can't connect to recaptcha" do
|
|
115
|
+
before(:each) do
|
|
116
|
+
Net::HTTP.stubs(:post_form).times(2).raises(Exception, "can't connect to recaptcha")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "should pass through if env var OFFLINE is set" do
|
|
120
|
+
lambda { do_request }.should raise_error(Exception)
|
|
121
|
+
ENV['OFFLINE'] = '1'
|
|
122
|
+
lambda { do_request }.should_not raise_error
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'spec'
|
|
3
|
+
require 'merb-core'
|
|
4
|
+
|
|
5
|
+
$:.push File.join(File.dirname(__FILE__), '..', 'lib')
|
|
6
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'merb-recaptcha')
|
|
7
|
+
|
|
8
|
+
default_options = {
|
|
9
|
+
:testing => true,
|
|
10
|
+
:adapter => 'runner',
|
|
11
|
+
:merb_root => File.dirname(__FILE__) / 'fixture',
|
|
12
|
+
:log_stream => STDOUT
|
|
13
|
+
}
|
|
14
|
+
options = default_options.merge($START_OPTIONS || {})
|
|
15
|
+
|
|
16
|
+
Merb.disable(:initfile)
|
|
17
|
+
Merb::BootLoader.after_app_loads do
|
|
18
|
+
Merb::Plugins.config[:merb_recaptcha][:public_key] = "QAAAAAA--public-key--AAAAAAQ"
|
|
19
|
+
Merb::Plugins.config[:merb_recaptcha][:private_key] = "QAAAAAA--private-key--AAAAAAAQ"
|
|
20
|
+
|
|
21
|
+
Merb::Router.prepare { default_routes }
|
|
22
|
+
Merb::RecaptchaMixin.const_set(:DO_NOT_IGNORE_RECAPTCHA_IN_TESTING_ENV, true)
|
|
23
|
+
end
|
|
24
|
+
Merb.start_environment(options)
|
|
25
|
+
|
|
26
|
+
Spec::Runner.configure do |config|
|
|
27
|
+
config.include Merb::Test::ViewHelper
|
|
28
|
+
config.include Merb::Test::RouteHelper
|
|
29
|
+
config.include Merb::Test::ControllerHelper
|
|
30
|
+
|
|
31
|
+
config.mock_with :mocha
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "ajax recaptcha", :shared => true do
|
|
35
|
+
it "should invoke Recaptcha.create" do
|
|
36
|
+
@response.should have_xpath("//script[contains(., 'Recaptcha.create')]")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should send public key to Recaptcha.create" do
|
|
40
|
+
@response.should have_xpath("//script[contains(., 'Recaptcha.create') and contains(., '#{Merb::Plugins.config[:merb_recaptcha][:public_key]}')]")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should not send private key to anything" do
|
|
44
|
+
@response.should_not have_xpath("//*[contains(., '#{Merb::Plugins.config[:merb_recaptcha][:private_key]}')]")
|
|
45
|
+
end
|
|
46
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: merb-recaptcha
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.3
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Anton Ageev
|
|
8
|
+
- Michael Johnston
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
|
|
13
|
+
date: 2009-10-08 00:00:00 +04:00
|
|
14
|
+
default_executable:
|
|
15
|
+
dependencies:
|
|
16
|
+
- !ruby/object:Gem::Dependency
|
|
17
|
+
name: merb-core
|
|
18
|
+
type: :runtime
|
|
19
|
+
version_requirement:
|
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
21
|
+
requirements:
|
|
22
|
+
- - ">="
|
|
23
|
+
- !ruby/object:Gem::Version
|
|
24
|
+
version: 1.0.0
|
|
25
|
+
version:
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: builder
|
|
28
|
+
type: :runtime
|
|
29
|
+
version_requirement:
|
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ~>
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: "2.0"
|
|
35
|
+
version:
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: rspec
|
|
38
|
+
type: :development
|
|
39
|
+
version_requirement:
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
requirements:
|
|
42
|
+
- - ">="
|
|
43
|
+
- !ruby/object:Gem::Version
|
|
44
|
+
version: 1.1.0
|
|
45
|
+
version:
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: mocha
|
|
48
|
+
type: :development
|
|
49
|
+
version_requirement:
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 0.9.3
|
|
55
|
+
version:
|
|
56
|
+
description: Merb plugin that provides helpers for recaptcha.net service
|
|
57
|
+
email: antage@gmail.com
|
|
58
|
+
executables: []
|
|
59
|
+
|
|
60
|
+
extensions: []
|
|
61
|
+
|
|
62
|
+
extra_rdoc_files:
|
|
63
|
+
- README.rdoc
|
|
64
|
+
- LICENSE
|
|
65
|
+
files:
|
|
66
|
+
- LICENSE
|
|
67
|
+
- README.rdoc
|
|
68
|
+
- Rakefile
|
|
69
|
+
- TODO
|
|
70
|
+
- merb-recaptcha.gemspec
|
|
71
|
+
- lib/merb-recaptcha/merbtasks.rb
|
|
72
|
+
- lib/merb-recaptcha/constants.rb
|
|
73
|
+
- lib/merb-recaptcha/exceptions.rb
|
|
74
|
+
- lib/merb-recaptcha/view_helpers.rb
|
|
75
|
+
- lib/merb-recaptcha/controller_mixin.rb
|
|
76
|
+
- lib/merb-recaptcha.rb
|
|
77
|
+
has_rdoc: true
|
|
78
|
+
homepage: http://github.com/antage/merb-recaptcha/
|
|
79
|
+
licenses: []
|
|
80
|
+
|
|
81
|
+
post_install_message:
|
|
82
|
+
rdoc_options:
|
|
83
|
+
- --main
|
|
84
|
+
- README.rdoc
|
|
85
|
+
require_paths:
|
|
86
|
+
- lib
|
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
88
|
+
requirements:
|
|
89
|
+
- - ">="
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: "0"
|
|
92
|
+
version:
|
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - ">="
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: "0"
|
|
98
|
+
version:
|
|
99
|
+
requirements: []
|
|
100
|
+
|
|
101
|
+
rubyforge_project: merb-recaptcha
|
|
102
|
+
rubygems_version: 1.3.5
|
|
103
|
+
signing_key:
|
|
104
|
+
specification_version: 3
|
|
105
|
+
summary: Merb plugin that provides helpers for recaptcha.net service
|
|
106
|
+
test_files:
|
|
107
|
+
- spec/spec_helper.rb
|
|
108
|
+
- spec/recaptcha_ajax_with_callback_spec.rb
|
|
109
|
+
- spec/recaptcha_noajax_with_noscript_spec.rb
|
|
110
|
+
- spec/recaptcha_noajax_with_options_spec.rb
|
|
111
|
+
- spec/recaptcha_ajax_spec.rb
|
|
112
|
+
- spec/recaptcha_ajax_with_jquery_spec.rb
|
|
113
|
+
- spec/recaptcha_ajax_with_options_spec.rb
|
|
114
|
+
- spec/recaptcha_noajax_without_noscript_spec.rb
|
|
115
|
+
- spec/recaptcha_valid_spec.rb
|
|
116
|
+
- spec/fixture/app/views/layout/application.html.erb
|
|
117
|
+
- spec/fixture/app/views/recaptcha/ajax_with_callback.html.erb
|
|
118
|
+
- spec/fixture/app/views/recaptcha/noajax_with_noscript.html.erb
|
|
119
|
+
- spec/fixture/app/views/recaptcha/ajax.html.erb
|
|
120
|
+
- spec/fixture/app/views/recaptcha/ajax_with_jquery.html.erb
|
|
121
|
+
- spec/fixture/app/views/recaptcha/noajax_with_options.html.erb
|
|
122
|
+
- spec/fixture/app/views/recaptcha/noajax_without_noscript.html.erb
|
|
123
|
+
- spec/fixture/app/views/recaptcha/ajax_with_options.html.erb
|
|
124
|
+
- spec/fixture/app/views/exceptions/not_acceptable.html.erb
|
|
125
|
+
- spec/fixture/app/views/exceptions/not_found.html.erb
|
|
126
|
+
- spec/fixture/app/controllers/exceptions.rb
|
|
127
|
+
- spec/fixture/app/controllers/application.rb
|
|
128
|
+
- spec/fixture/app/controllers/recaptcha.rb
|
|
129
|
+
- spec/fixture/app/helpers/recaptcha_helpers.rb
|
|
130
|
+
- spec/fixture/app/helpers/global_helpers.rb
|