rack-picatcha 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -0
- data/LICENSE +20 -0
- data/README.md +123 -0
- data/Rakefile +12 -0
- data/lib/rack/picatcha.rb +146 -0
- data/lib/rack/picatcha/helpers.rb +90 -0
- data/rack-picatcha.gemspec +23 -0
- data/test/helpers_test.rb +176 -0
- data/test/picatcha_test.rb +58 -0
- data/test/teststrap.rb +45 -0
- metadata +156 -0
data/.gitignore
ADDED
File without changes
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 James Ayvaz
|
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.md
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
Dropin replacement for rack-recaptcha that uses picatcha verification.
|
2
|
+
|
3
|
+
## How to Use
|
4
|
+
|
5
|
+
### Configuration
|
6
|
+
|
7
|
+
First, install the library with:
|
8
|
+
[sudo] gem install rack-picatcha
|
9
|
+
|
10
|
+
You have to require 'rack-picatcha' in your gemfile.
|
11
|
+
|
12
|
+
````ruby
|
13
|
+
## Gemfile
|
14
|
+
gem 'rack-picatcha', :require => 'rack/picatcha'
|
15
|
+
````
|
16
|
+
|
17
|
+
|
18
|
+
Available options for `Rack::Picatcha` middleware are:
|
19
|
+
|
20
|
+
* :public_key -- your Picatcha API public key *(required)*
|
21
|
+
* :private_key -- your Picatcha API private key *(required)*
|
22
|
+
* :proxy_host -- the HTTP Proxy hostname *(optional)*
|
23
|
+
* :proxy_port -- the HTTP Proxy port *(optional)*
|
24
|
+
* :proxy_user -- the HTTP Proxy user *(optional, omit unless the proxy requires it)*
|
25
|
+
* :proxy_password -- the HTTP Proxy password *(optional, omit unless the proxy requires it)*
|
26
|
+
|
27
|
+
Now configure your app to use the middleware. This might be different across each web framework.
|
28
|
+
Only tested with Sinatra
|
29
|
+
|
30
|
+
#### Sinatra
|
31
|
+
|
32
|
+
````ruby
|
33
|
+
## app.rb
|
34
|
+
use Rack::Picatcha, :public_key => 'KEY', :private_key => 'SECRET'
|
35
|
+
helpers Rack::Picatcha::Helpers
|
36
|
+
````
|
37
|
+
|
38
|
+
#### Padrino
|
39
|
+
|
40
|
+
````ruby
|
41
|
+
## app/app.rb
|
42
|
+
use Rack::Picatcha, :public_key => 'KEY', :private_key => 'SECRET'
|
43
|
+
helpers Rack::Picatcha::Helpers
|
44
|
+
````
|
45
|
+
|
46
|
+
|
47
|
+
#### Rails
|
48
|
+
|
49
|
+
````ruby
|
50
|
+
## application.rb:
|
51
|
+
module YourRailsAppName
|
52
|
+
class Application < Rails::Application
|
53
|
+
...
|
54
|
+
config.gem 'rack-picatcha', :lib => 'rack/picatcha'
|
55
|
+
config.middleware.use Rack::Picatcha, :public_key => 'KEY', :private_key => 'SECRET'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
## application_helper.rb or whatever helper you want it in.
|
60
|
+
module ApplicationHelper
|
61
|
+
include Rack::Picatcha::Helpers
|
62
|
+
end
|
63
|
+
|
64
|
+
## application_controller.rb or whatever controller you want it in.
|
65
|
+
class ApplicationController < ActionController::Base
|
66
|
+
...
|
67
|
+
include Rack::Picatcha::Helpers
|
68
|
+
...
|
69
|
+
end
|
70
|
+
````
|
71
|
+
|
72
|
+
### Helpers
|
73
|
+
|
74
|
+
The `Rack::Picatcha::Helpers` module (for Sinatra, Rails, Padrino) adds these methods to your app:
|
75
|
+
|
76
|
+
Return a picatcha form
|
77
|
+
```ruby
|
78
|
+
picatcha_tag :challenge, :public_key => PUBLIC_KEY
|
79
|
+
```
|
80
|
+
|
81
|
+
To test whether or not the verification passed, you can use:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
picatcha_valid?
|
85
|
+
```
|
86
|
+
|
87
|
+
or
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
picatcha_valid? :picatcha => params[:picatcha], :private_key => "#{recaptcha_privatekey}"
|
91
|
+
```
|
92
|
+
|
93
|
+
The `picatcha_valid?` helper can also be overloaded during tests. You
|
94
|
+
can set its response to either true or false by doing the following:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
# Have picatcha_valid? return true
|
98
|
+
Rack::Picatcha.test_mode!
|
99
|
+
|
100
|
+
# Or have it return false
|
101
|
+
Rack::Picatcha.test_mode! :return => false
|
102
|
+
```
|
103
|
+
|
104
|
+
|
105
|
+
### Contributors
|
106
|
+
|
107
|
+
James Ayvaz - [ayvazj](https://github.com/ayvazj)
|
108
|
+
|
109
|
+
* drop in replacement for rack-recaptcha
|
110
|
+
|
111
|
+
#### Note on Patches/Pull Requests
|
112
|
+
|
113
|
+
* Fork the project.
|
114
|
+
* Make your feature addition or bug fix.
|
115
|
+
* Add tests for it. This is important so I don't break it in a
|
116
|
+
future version unintentionally.
|
117
|
+
* Commit, do not mess with rakefile, version, or history.
|
118
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
119
|
+
* Send me a pull request. Bonus points for topic branches.
|
120
|
+
|
121
|
+
#### Copyright
|
122
|
+
|
123
|
+
Copyright (c) 2012 James Ayvaz. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake/testtask'
|
5
|
+
Rake::TestTask.new(:test) do |test|
|
6
|
+
test.libs << 'lib' << 'test'
|
7
|
+
test.pattern = 'test/**/*_test.rb'
|
8
|
+
test.warning = true
|
9
|
+
test.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
task :default => [:test]
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require File.expand_path '../picatcha/helpers', __FILE__
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
class Picatcha
|
6
|
+
API_URL = 'http://api.picatcha.com'
|
7
|
+
API_SECURE_URL = 'https://api.picatcha.com'
|
8
|
+
VERIFY_URL = 'http://api.picatcha.com/v'
|
9
|
+
CHALLENGE_FIELD = 'picatcha'
|
10
|
+
|
11
|
+
SKIP_VERIFY_ENV = ['test', 'cucumber']
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_accessor :private_key, :public_key, :test_mode, :proxy_host, :proxy_port, :proxy_user, :proxy_password
|
15
|
+
|
16
|
+
def test_mode!(options = {})
|
17
|
+
value = options[:return]
|
18
|
+
self.test_mode = value.nil? ? true : options[:return]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Initialize the Rack Middleware. Some of the available options are:
|
23
|
+
# :public_key -- your Picatcha API public key *(required)*
|
24
|
+
# :private_key -- your Picatcha API private key *(required)*
|
25
|
+
#
|
26
|
+
def initialize(app,options = {})
|
27
|
+
@app = app
|
28
|
+
@paths = options[:paths] && [options[:paths]].flatten.compact
|
29
|
+
self.class.private_key = options[:private_key]
|
30
|
+
self.class.public_key = options[:public_key]
|
31
|
+
self.class.proxy_host = options[:proxy_host]
|
32
|
+
self.class.proxy_port = options[:proxy_port]
|
33
|
+
self.class.proxy_user = options[:proxy_user]
|
34
|
+
self.class.proxy_password = options[:proxy_password]
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(env)
|
38
|
+
# LOGGER.debug "def call"
|
39
|
+
dup._call(env)
|
40
|
+
end
|
41
|
+
|
42
|
+
def _call(env)
|
43
|
+
request = Request.new(env)
|
44
|
+
# LOGGER.debug "def _call env=#{env} params=#{request.params}"
|
45
|
+
if request.params[CHALLENGE_FIELD]
|
46
|
+
value, msg = verify({
|
47
|
+
:request => request,
|
48
|
+
:ip => request.ip,
|
49
|
+
:challenge => request.params[CHALLENGE_FIELD]
|
50
|
+
})
|
51
|
+
env.merge!('picatcha.valid' => value == 'true', 'picatcha.msg' => msg)
|
52
|
+
end
|
53
|
+
@app.call(env)
|
54
|
+
end
|
55
|
+
|
56
|
+
def verify(options = {})
|
57
|
+
if !options.is_a? Hash
|
58
|
+
options = {:model => options}
|
59
|
+
end
|
60
|
+
|
61
|
+
model = options[:model]
|
62
|
+
request = options[:request]
|
63
|
+
|
64
|
+
return Rack::Picatcha.verify_picatcha({
|
65
|
+
:private_key => Rack::Picatcha.private_key,
|
66
|
+
:ipaddr => request.ip,
|
67
|
+
:proxy_host => self.class.proxy_host,
|
68
|
+
:proxy_port => self.class.proxy_port,
|
69
|
+
:proxy_user => self.class.proxy_user,
|
70
|
+
:proxy_password => self.class.proxy_password,
|
71
|
+
:picatcha => request.params["picatcha"]
|
72
|
+
})
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.verify_picatcha(options = {})
|
76
|
+
if !options.is_a? Hash
|
77
|
+
options = {:model => options}
|
78
|
+
end
|
79
|
+
|
80
|
+
ipaddr = options[:ipaddr]
|
81
|
+
proxy_host = options[:proxy_host]
|
82
|
+
proxy_port = options[:proxy_port]
|
83
|
+
proxy_user = options[:proxy_user]
|
84
|
+
proxy_password = options[:proxy_password]
|
85
|
+
|
86
|
+
private_key = options[:private_key]
|
87
|
+
picatchadata = options[:picatcha]
|
88
|
+
|
89
|
+
data = {
|
90
|
+
"k" => private_key,
|
91
|
+
"ip" => ipaddr,
|
92
|
+
"ua"=> "Rack-Picatcha Ruby Gem",
|
93
|
+
"s" => picatchadata[:stages], #the number of stages
|
94
|
+
"t" => picatchadata[:token], #the challenge token
|
95
|
+
"r" => picatchadata[:r] #the array of images
|
96
|
+
}
|
97
|
+
|
98
|
+
payload = data.to_json
|
99
|
+
# LOGGER.debug "payload = #{payload}"
|
100
|
+
|
101
|
+
uri = URI.parse(VERIFY_URL)
|
102
|
+
http = Net::HTTP.start(uri.host, uri.port)
|
103
|
+
|
104
|
+
if proxy_host && proxy_port
|
105
|
+
http = Net::HTTP.Proxy(proxy_host,
|
106
|
+
proxy_port,
|
107
|
+
proxy_user,
|
108
|
+
proxy_password).start(uri.host, uri.port)
|
109
|
+
end
|
110
|
+
|
111
|
+
request = Net::HTTP::Post.new(uri.path)
|
112
|
+
request.body = payload
|
113
|
+
response = http.request(request)
|
114
|
+
|
115
|
+
# debugging info
|
116
|
+
# LOGGER.debug "response.body = #{response.body}"
|
117
|
+
|
118
|
+
if response.body !=nil
|
119
|
+
parsed_json = JSON(response.body)
|
120
|
+
else
|
121
|
+
return false, 'No reponse captured'
|
122
|
+
end
|
123
|
+
|
124
|
+
# LOGGER.error "error? = #{parsed_json["e"]}"
|
125
|
+
|
126
|
+
error = parsed_json["e"]
|
127
|
+
|
128
|
+
# so far just a simple if.. else to check if the picatcha was
|
129
|
+
# solved correctly. will revisit later and make it more
|
130
|
+
# verbose
|
131
|
+
if parsed_json["s"]==true
|
132
|
+
return true, ""
|
133
|
+
else
|
134
|
+
message = "Sorry, you incorrectly filled out Picatcha. Please try again."
|
135
|
+
message = I18n.translate(:'picatcha.errors.verification_failed', :default => message) if defined?(I18n)
|
136
|
+
return false, message
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
class PicatchaError < StandardError
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class Picatcha
|
5
|
+
module Helpers
|
6
|
+
|
7
|
+
DEFAULT= {
|
8
|
+
:height => 300,
|
9
|
+
:width => 500,
|
10
|
+
:row => 3,
|
11
|
+
:cols => 5,
|
12
|
+
:format => '2',
|
13
|
+
:style => '#2a1f19',
|
14
|
+
:link => '1',
|
15
|
+
:img_size => '75',
|
16
|
+
:noise_level => '2',
|
17
|
+
:noise_type => '0',
|
18
|
+
:lang => 'en',
|
19
|
+
:lang_override => '0',
|
20
|
+
:ssl => false
|
21
|
+
}
|
22
|
+
|
23
|
+
# Helper method to output a picatcha form. Some of the available
|
24
|
+
# types you can have are:
|
25
|
+
#
|
26
|
+
# :challenge - Returns a javascript picatcha form
|
27
|
+
# :noscript - Return a non-javascript picatcha form
|
28
|
+
# :ajax - Return a ajax picatcha form
|
29
|
+
#
|
30
|
+
# You also have a few available options:
|
31
|
+
#
|
32
|
+
# For :challenge and :noscript
|
33
|
+
# :public_key - Set the public key. Overrides the key set in Middleware option
|
34
|
+
def picatcha_tag(type= :noscript, options={})
|
35
|
+
# Default options
|
36
|
+
options = DEFAULT.merge(options)
|
37
|
+
options[:public_key] ||= Rack::Picatcha.public_key
|
38
|
+
path = options[:ssl] ? Rack::Picatcha::API_SECURE_URL : Rack::Picatcha::API_URL
|
39
|
+
|
40
|
+
raise PicatchaError, "No public key specified." unless options[:public_key].to_s != ''
|
41
|
+
error = options[:error] ||= (defined? flash ? flash[:picatcha_error] : "")
|
42
|
+
html = ""
|
43
|
+
elm_id = "picatcha"
|
44
|
+
|
45
|
+
html << <<-EOS
|
46
|
+
<script type="text/javascript" src="#{path}/static/client/jquery.min.js"></script>
|
47
|
+
<script type="text/javascript" src="#{path}/static/client/picatcha.js"></script>
|
48
|
+
<link href="#{path}/static/client/picatcha.css" rel="stylesheet" type="text/css">
|
49
|
+
<script>Picatcha.PUBLIC_KEY="#{options[:public_key]}";
|
50
|
+
Picatcha.setCustomization({"format":"#{options[:format]}","color":"#{options[:style]}","link":"#{options[:link]}","image_size":"#{options[:img_size]}","lang":"#{options[:lang]}","langOverride":"#{options[:lang_override]}","noise_level":"#{options[:noise_level]}","noise_type":"#{options[:noise_type]}"});
|
51
|
+
window.onload=function(){Picatcha.create("#{elm_id}", {});};</script>
|
52
|
+
<div id="#{elm_id}"></div>
|
53
|
+
EOS
|
54
|
+
|
55
|
+
if options[:display]
|
56
|
+
%{<script type="text/javascript">
|
57
|
+
var PicatchaOptions = #{options[:display].to_json};
|
58
|
+
</script>}.gsub(/^ +/, '')
|
59
|
+
else
|
60
|
+
''
|
61
|
+
end + html
|
62
|
+
end
|
63
|
+
|
64
|
+
# Helper to return whether the picatcha was accepted.
|
65
|
+
def picatcha_valid?(options={})
|
66
|
+
# LOGGER.debug "def picatchs_valid? options=#{options}"
|
67
|
+
picatchadata = options[:picatcha] || ""
|
68
|
+
private_key = options[:private_key] || Rack::Picatcha.private_key
|
69
|
+
if picatchadata.to_s == "" then
|
70
|
+
test = Rack::Picatcha.test_mode
|
71
|
+
test.nil? ? request.env['picatcha.valid'] : test
|
72
|
+
else
|
73
|
+
retval, msg = Rack::Picatcha.verify_picatcha({
|
74
|
+
:private_key => private_key,
|
75
|
+
:ipaddr => request.ip,
|
76
|
+
:picatcha => picatchadata
|
77
|
+
})
|
78
|
+
return retval
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def uri_parser
|
85
|
+
@uri_parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{rack-picatcha}
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.required_rubygems_version = ">=1.3.6"
|
5
|
+
s.authors = ["James Ayvaz"]
|
6
|
+
s.date = %q{2012-10-04}
|
7
|
+
s.description = %q{Rack middleware verification using Picatcha API.}
|
8
|
+
s.email = %q{james.ayvaz@gmail.com}
|
9
|
+
s.extra_rdoc_files = ["LICENSE", "README.md"]
|
10
|
+
s.files = %w{.gitignore LICENSE README.md Rakefile rack-picatcha.gemspec} + Dir.glob("{lib,test}/**/*")
|
11
|
+
s.homepage = %q{http://github.com/ayvazj/rack-picatcha}
|
12
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
s.rubygems_version = %q{1.3.7}
|
15
|
+
s.summary = %q{Rack middleware for Picatcha}
|
16
|
+
s.test_files = Dir.glob("test/**/*")
|
17
|
+
s.add_runtime_dependency "json", ">= 0"
|
18
|
+
s.add_development_dependency "rake", "~> 0.9.2"
|
19
|
+
s.add_development_dependency "riot", "~> 0.12.3"
|
20
|
+
s.add_development_dependency "rack-test", "~> 0.5.7"
|
21
|
+
s.add_development_dependency "fakeweb", "~> 1.3.0"
|
22
|
+
s.add_development_dependency "rr", "~> 1.0.2"
|
23
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require File.expand_path '../teststrap', __FILE__
|
2
|
+
|
3
|
+
class HelperTest
|
4
|
+
attr_accessor :request
|
5
|
+
include Rack::Picatcha::Helpers
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@request = HelperTest::Request.new
|
9
|
+
end
|
10
|
+
|
11
|
+
class Request
|
12
|
+
attr_accessor :env
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# With "attr_accessor :request" HelperTest has "request" defined as a method
|
18
|
+
# even when @request is set to nil
|
19
|
+
#
|
20
|
+
# defined?(request)
|
21
|
+
# => method
|
22
|
+
# request
|
23
|
+
# => nil
|
24
|
+
# self
|
25
|
+
# => #<HelperTest:0x00000002125000 @request=nil>
|
26
|
+
class HelperTestWithoutRequest
|
27
|
+
include Rack::Picatcha::Helpers
|
28
|
+
end
|
29
|
+
|
30
|
+
context "Rack::Picatcha::Helpers" do
|
31
|
+
helper(:helper_test) { HelperTest.new }
|
32
|
+
|
33
|
+
setup { Rack::Picatcha.public_key = '0'*40 }
|
34
|
+
|
35
|
+
context "picatcha_tag" do
|
36
|
+
|
37
|
+
context "ajax" do
|
38
|
+
context "with display" do
|
39
|
+
setup do
|
40
|
+
mock(helper_test.request.env).[]('picatcha.msg').returns(nil)
|
41
|
+
helper_test.picatcha_tag(:ajax,:display => {:theme => 'red'})
|
42
|
+
end
|
43
|
+
|
44
|
+
asserts_topic('has js').matches %r{picatcha_ajax.js}
|
45
|
+
asserts_topic('has div').matches %r{<div id="ajax_picatcha"></div>}
|
46
|
+
asserts_topic('has display').matches %r{PicatchaOptions}
|
47
|
+
asserts_topic('has theme').matches %r{"theme":"red"}
|
48
|
+
end
|
49
|
+
|
50
|
+
context "without display" do
|
51
|
+
setup do
|
52
|
+
mock(helper_test.request.env).[]('picatcha.msg').returns(nil)
|
53
|
+
helper_test.picatcha_tag(:ajax)
|
54
|
+
end
|
55
|
+
|
56
|
+
asserts_topic('has js').matches %r{picatcha_ajax.js}
|
57
|
+
asserts_topic('has div').matches %r{<div id="ajax_picatcha"></div>}
|
58
|
+
denies_topic('has display').matches %r{PicatchaOptions}
|
59
|
+
denies_topic('has theme').matches %r{"theme":"red"}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "noscript" do
|
64
|
+
setup do
|
65
|
+
mock(helper_test.request.env).[]('picatcha.msg').returns(nil)
|
66
|
+
helper_test.picatcha_tag :noscript, :public_key => "hello_world_world", :language => :en
|
67
|
+
end
|
68
|
+
|
69
|
+
asserts_topic("iframe").matches %r{iframe}
|
70
|
+
asserts_topic("no script tag").matches %r{<noscript>}
|
71
|
+
asserts_topic("public key").matches %r{hello_world_world}
|
72
|
+
asserts_topic("has language").matches %r{hl=en}
|
73
|
+
denies_topic("has js").matches %r{picatcha_ajax.js}
|
74
|
+
end
|
75
|
+
|
76
|
+
context "challenge" do
|
77
|
+
setup do
|
78
|
+
mock(helper_test.request.env).[]('picatcha.msg').returns(nil)
|
79
|
+
helper_test.picatcha_tag(:challenge, :language => :en)
|
80
|
+
end
|
81
|
+
|
82
|
+
asserts_topic("has script tag").matches %r{script}
|
83
|
+
asserts_topic("has challenge js").matches %r{challenge}
|
84
|
+
denies_topic("has js").matches %r{picatcha_ajax.js}
|
85
|
+
denies_topic("has display").matches %r{PicatchaOptions}
|
86
|
+
asserts_topic("has public_key").matches %r{#{'0'*40}}
|
87
|
+
asserts_topic("has language").matches %r{hl=en}
|
88
|
+
end
|
89
|
+
|
90
|
+
context "server" do
|
91
|
+
|
92
|
+
asserts("using ssl url") do
|
93
|
+
mock(helper_test.request.env).[]('picatcha.msg').returns(nil)
|
94
|
+
helper_test.picatcha_tag(:challenge, :ssl => true)
|
95
|
+
end.matches %r{#{Rack::Picatcha::API_SECURE_URL}}
|
96
|
+
|
97
|
+
asserts("using non ssl url") do
|
98
|
+
mock(helper_test.request.env).[]('picatcha.msg').returns(nil)
|
99
|
+
helper_test.picatcha_tag(:ajax)
|
100
|
+
end.matches %r{#{Rack::Picatcha::API_URL}}
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
context "picatcha_tag_errors" do
|
106
|
+
context "challenge with error" do
|
107
|
+
setup do
|
108
|
+
mock(helper_test.request.env).[]('picatcha.msg').returns("Sample Error")
|
109
|
+
helper_test.picatcha_tag(:challenge)
|
110
|
+
end
|
111
|
+
|
112
|
+
asserts_topic("has script tag").matches %r{script}
|
113
|
+
asserts_topic("has challenge js").matches %r{challenge}
|
114
|
+
denies_topic("has js").matches %r{picatcha_ajax.js}
|
115
|
+
denies_topic("has display").matches %r{PicatchaOptions}
|
116
|
+
asserts_topic("has public_key").matches %r{#{'0'*40}}
|
117
|
+
asserts_topic("has previous error").matches %r{Sample%20Error}
|
118
|
+
end
|
119
|
+
|
120
|
+
context "noscript with error" do
|
121
|
+
setup do
|
122
|
+
mock(helper_test.request.env).[]('picatcha.msg').returns("Sample Error")
|
123
|
+
helper_test.picatcha_tag :noscript, :public_key => "hello_world_world"
|
124
|
+
end
|
125
|
+
|
126
|
+
asserts_topic("iframe").matches %r{iframe}
|
127
|
+
asserts_topic("no script tag").matches %r{<noscript>}
|
128
|
+
asserts_topic("public key").matches %r{hello_world_world}
|
129
|
+
denies_topic("has js").matches %r{picatcha_ajax.js}
|
130
|
+
asserts_topic("has previous error").matches %r{Sample%20Error}
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
context "picatcha_valid?" do
|
136
|
+
|
137
|
+
asserts "that it passes when picatcha.valid is true" do
|
138
|
+
Rack::Picatcha.test_mode = nil
|
139
|
+
mock(helper_test.request.env).[]('picatcha.valid').returns(true)
|
140
|
+
helper_test.picatcha_valid?
|
141
|
+
end
|
142
|
+
|
143
|
+
denies "that it passes when picatcha.valid is false" do
|
144
|
+
Rack::Picatcha.test_mode = nil
|
145
|
+
mock(helper_test.request.env).[]('picatcha.valid').returns(false)
|
146
|
+
helper_test.picatcha_valid?
|
147
|
+
end
|
148
|
+
|
149
|
+
asserts "that it passes when test mode set to pass" do
|
150
|
+
Rack::Picatcha.test_mode!
|
151
|
+
helper_test.picatcha_valid?
|
152
|
+
end
|
153
|
+
|
154
|
+
denies "that it passes when test mode set to fail" do
|
155
|
+
Rack::Picatcha.test_mode! :return => false
|
156
|
+
helper_test.picatcha_valid?
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
context Rack::Picatcha::Helpers do
|
164
|
+
helper(:helper_test) { HelperTestWithoutRequest.new }
|
165
|
+
context "request object not available. Rack-picatcha shouldn't die" do
|
166
|
+
setup do
|
167
|
+
helper_test.picatcha_tag(:challenge)
|
168
|
+
end
|
169
|
+
|
170
|
+
asserts_topic("has script tag").matches %r{script}
|
171
|
+
asserts_topic("has challenge js").matches %r{challenge}
|
172
|
+
denies_topic("has js").matches %r{picatcha_ajax.js}
|
173
|
+
denies_topic("has display").matches %r{PicatchaOptions}
|
174
|
+
asserts_topic("has public_key").matches %r{#{'0'*40}}
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.expand_path './teststrap'
|
2
|
+
|
3
|
+
FakeWeb.allow_net_connect = false
|
4
|
+
context "Rack::Picatcha" do
|
5
|
+
|
6
|
+
context "basic request" do
|
7
|
+
setup { get("/") ; last_response }
|
8
|
+
|
9
|
+
asserts(:status).equals 200
|
10
|
+
asserts(:body).equals "Hello world"
|
11
|
+
end
|
12
|
+
|
13
|
+
context "exposes" do
|
14
|
+
setup { Rack::Picatcha }
|
15
|
+
|
16
|
+
asserts(:private_key).equals PRIVATE_KEY
|
17
|
+
asserts(:public_key).equals PUBLIC_KEY
|
18
|
+
end
|
19
|
+
|
20
|
+
context "#test_mode!" do
|
21
|
+
setup { Rack::Picatcha }
|
22
|
+
|
23
|
+
asserts "that it sets @@test_mode to be true" do
|
24
|
+
topic.test_mode!
|
25
|
+
topic.test_mode
|
26
|
+
end
|
27
|
+
|
28
|
+
denies "that it sets @@test_mode to be true if option set to false" do
|
29
|
+
topic.test_mode! :return => false
|
30
|
+
topic.test_mode
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "login path" do
|
35
|
+
|
36
|
+
asserts "GET login" do
|
37
|
+
get '/login'
|
38
|
+
last_response.body
|
39
|
+
end.equals 'login'
|
40
|
+
|
41
|
+
|
42
|
+
asserts "POST login passes and" do
|
43
|
+
puts Rack::Picatcha::VERIFY_URL
|
44
|
+
FakeWeb.register_uri(:post, Rack::Picatcha::VERIFY_URL, :body => "true\nsuccess")
|
45
|
+
puts "HERE2"
|
46
|
+
post("/login", 'picatcha_challenge_field' => 'challenge', 'picatcha_response_field' => 'response')
|
47
|
+
puts "HERE3"
|
48
|
+
last_response.body
|
49
|
+
end.equals 'post login'
|
50
|
+
|
51
|
+
asserts "POST login fails and" do
|
52
|
+
FakeWeb.register_uri(:post, Rack::Picatcha::VERIFY_URL, :body => "false\nfailed")
|
53
|
+
post("/login", 'picatcha_challenge_field' => 'challenge', 'picatcha_response_field' => 'response')
|
54
|
+
last_response.body
|
55
|
+
end.equals 'post fail'
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/test/teststrap.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'rack/mock'
|
4
|
+
require 'rack/utils'
|
5
|
+
require 'rack/session/cookie'
|
6
|
+
require 'rack/builder'
|
7
|
+
require 'rr'
|
8
|
+
require 'riot'
|
9
|
+
require 'riot/rr'
|
10
|
+
require 'fakeweb'
|
11
|
+
require File.expand_path '../../lib/rack/picatcha', __FILE__
|
12
|
+
|
13
|
+
PUBLIC_KEY = '0'*40
|
14
|
+
PRIVATE_KEY = 'X'*40
|
15
|
+
|
16
|
+
class Riot::Situation
|
17
|
+
include Rack::Test::Methods
|
18
|
+
|
19
|
+
def app
|
20
|
+
main_app = lambda { |env|
|
21
|
+
request = Rack::Request.new(env)
|
22
|
+
return_code, body_text =
|
23
|
+
case request.path
|
24
|
+
when '/' then [200,'Hello world']
|
25
|
+
when '/login'
|
26
|
+
if request.post?
|
27
|
+
env['picatcha.valid'] ? [200, 'post login'] : [200, 'post fail']
|
28
|
+
else
|
29
|
+
[200,'login']
|
30
|
+
end
|
31
|
+
else
|
32
|
+
[404,'Nothing here']
|
33
|
+
end
|
34
|
+
[return_code,{'Content-type' => 'text/plain'}, [body_text]]
|
35
|
+
}
|
36
|
+
|
37
|
+
builder = Rack::Builder.new
|
38
|
+
builder.use Rack::Picatcha, :private_key => PRIVATE_KEY, :public_key => PUBLIC_KEY
|
39
|
+
builder.run main_app
|
40
|
+
builder.to_app
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Riot::Context
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-picatcha
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- James Ayvaz
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.9.2
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.9.2
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: riot
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.12.3
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.12.3
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rack-test
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.5.7
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.5.7
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: fakeweb
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.3.0
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.3.0
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rr
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.0.2
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.0.2
|
110
|
+
description: Rack middleware verification using Picatcha API.
|
111
|
+
email: james.ayvaz@gmail.com
|
112
|
+
executables: []
|
113
|
+
extensions: []
|
114
|
+
extra_rdoc_files:
|
115
|
+
- LICENSE
|
116
|
+
- README.md
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- LICENSE
|
120
|
+
- README.md
|
121
|
+
- Rakefile
|
122
|
+
- rack-picatcha.gemspec
|
123
|
+
- lib/rack/picatcha/helpers.rb
|
124
|
+
- lib/rack/picatcha.rb
|
125
|
+
- test/helpers_test.rb
|
126
|
+
- test/picatcha_test.rb
|
127
|
+
- test/teststrap.rb
|
128
|
+
homepage: http://github.com/ayvazj/rack-picatcha
|
129
|
+
licenses: []
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options:
|
132
|
+
- --charset=UTF-8
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ! '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ! '>='
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: 1.3.6
|
147
|
+
requirements: []
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 1.8.24
|
150
|
+
signing_key:
|
151
|
+
specification_version: 3
|
152
|
+
summary: Rack middleware for Picatcha
|
153
|
+
test_files:
|
154
|
+
- test/helpers_test.rb
|
155
|
+
- test/picatcha_test.rb
|
156
|
+
- test/teststrap.rb
|