rack-picatcha 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.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
|