rack-bouncer 1.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ .DS_Store
3
+ *.gem
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ree-1.8.7-2011.03@rack-bouncer --create
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # encoding: UTF-8
2
+ source :rubygems
3
+
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,18 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rack-bouncer (1.2)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ minitest (2.11.1)
10
+ rack (1.4.1)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ minitest (~> 2.11.1)
17
+ rack (~> 1.4.1)
18
+ rack-bouncer!
data/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # rack-bouncer
2
+
3
+ A Rack middleware that expels undesirable browsers out of your website. This project lovingly extends the `rack-noie6` gem.
4
+
5
+ | _Browser_ | _Undesirable Versions_ |
6
+ |-------------------|------------------------|
7
+ | Internet Explorer | < 8 |
8
+ | AOL | All |
9
+
10
+ ## usage
11
+
12
+ gem install rack-bouncer
13
+ require "rack/bouncer"
14
+
15
+ The default redirects users to [Browse Happy](http://browsehappy.com/):
16
+
17
+ use Rack::Bouncer
18
+
19
+ You can redirect users to a page in your website:
20
+
21
+ use Rack::Bouncer, :redirect => "/bouncer.html"
22
+
23
+ You can redirect users to a URL as well:
24
+
25
+ use Rack::Bouncer, :redirect => "http://slashdot.org"
26
+
27
+ You can even specify a minimum version of IE like so:
28
+
29
+ use Rack::Bouncer, :redirect => "http://slashdot.org", :minimum_ie => 6.0
30
+
31
+ You can even specify a set of safe paths:
32
+
33
+ use Rack::Bouncer, :safe_paths => ["/assets", "/images", "/stylesheets", "/javascripts", "/feedback"]
34
+
35
+ *NOTE:* By default, the above paths are safe already.
36
+
37
+ ## contributing
38
+
39
+ Pull requests are very welcome.
40
+
41
+ ## acknowledgments
42
+
43
+ Thanks to [juliocesar](http://github.com/juliocesar), [sant0sk1](http://github.com/sant0sk1), [wjessop](http://github.com/wjessop), and [robomc](https://github.com/robomc) for their contributions to `rack-noie6`.
44
+
45
+ ## license
46
+
47
+ Copyright (c) 2012 Ryan Sobol
48
+
49
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
50
+
51
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
52
+
53
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ # encoding: UTF-8
2
+ require "rake/testtask"
3
+
4
+ task :default => [:test]
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs.push "lib"
8
+ t.test_files = FileList["test/**/*_test.rb"]
9
+ t.verbose = true
10
+ end
11
+
12
+ ###################################################################################################
13
+
14
+ require File.expand_path("lib/rack/bouncer", File.dirname(__FILE__))
15
+
16
+ namespace :gem do
17
+ desc "Builds a gem from the current project's Gem::Specification"
18
+ task :build do
19
+ puts "==> Building RubyGem"
20
+
21
+ if `git status` !~ /working directory clean/
22
+ abort " Cannot build RubyGem because the working directory is not clean."
23
+ end
24
+
25
+ system "gem build rack-bouncer.gemspec"
26
+ end
27
+
28
+ desc "Removes the gem file for the current project"
29
+ task :clean do
30
+ puts "==> Cleaning up RubyGem build"
31
+ jeweler do |gem_file|
32
+ rm gem_file, :verbose => false
33
+ puts " Removed #{gem_file}"
34
+ end
35
+ end
36
+
37
+ desc "Pushes the current gem to RubyGems.org"
38
+ task :push do
39
+ puts "==> Pushing RubyGem"
40
+ jeweler { |gem_file| system "gem push #{gem_file}"}
41
+ end
42
+
43
+ desc "Builds, pushes, and cleans a gem for the current project"
44
+ task :release do
45
+ Rake::Task["gem:build"].invoke
46
+ Rake::Task["gem:push"].invoke
47
+ Rake::Task["gem:clean"].invoke
48
+ end
49
+
50
+ def jeweler(&block)
51
+ file = "rack-bouncer-#{Rack::Bouncer::VERSION}.gem"
52
+ if File.exists?(file)
53
+ yield file
54
+ else
55
+ puts " RubyGem #{file.inspect} does not exist"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: UTF-8
2
+
3
+ module Rack
4
+ class Bouncer
5
+ VERSION = "1.2"
6
+
7
+ DEFAULT_OPTIONS = {
8
+ :safe_paths => ["/assets", "/images", "/stylesheets", "/javascripts", "/feedback"],
9
+ :redirect => "http://browsehappy.com/",
10
+ :minimum_ie => 8.0
11
+ }
12
+
13
+ def initialize(app, options = {})
14
+ @app = app
15
+ @options = DEFAULT_OPTIONS.merge(options)
16
+ end
17
+
18
+ def call(env)
19
+ if !safe_path(env) && (ie6_found_in?(env) || aol_found_in?(env))
20
+ kick_it
21
+ else
22
+ @app.call(env)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def safe_path(env)
29
+ path = env["PATH_INFO"]
30
+ safe_paths = @options[:safe_paths].join("|")
31
+
32
+ path == @options[:redirect] || path =~ Regexp.new("^(#{safe_paths})")
33
+ end
34
+
35
+ def ie6_found_in?(env)
36
+ if env["HTTP_USER_AGENT"]
37
+ is_ie?(env["HTTP_USER_AGENT"]) and ie_version(env["HTTP_USER_AGENT"]) < @options[:minimum_ie] and @options[:redirect] != env["PATH_INFO"]
38
+ end
39
+ end
40
+
41
+ def is_ie?(ua_string)
42
+ # We need at least one digit to be able to get the version, hence the \d
43
+ ua_string.match(/MSIE \d/) ? true : false
44
+ end
45
+
46
+ def aol_found_in?(env)
47
+ if env["HTTP_USER_AGENT"]
48
+ is_aol?(env["HTTP_USER_AGENT"])
49
+ end
50
+ end
51
+
52
+ def is_aol?(ua_string)
53
+ ua_string.match(/AOL \d/) ? true : false
54
+ end
55
+
56
+ def ie_version(ua_string)
57
+ ua_string.match(/MSIE (\S+)/)[1].to_f
58
+ end
59
+
60
+ def kick_it
61
+ [302, {"Location" => @options[:redirect], "Content-Type" => "text/html"}, "Browser not supported"]
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path("lib/rack/bouncer", File.dirname(__FILE__))
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "rack-bouncer"
6
+ s.version = Rack::Bouncer::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Jerod Santo", "Julio Cesar Ody", "Will Jessop", "Ryan Sobol"]
9
+ s.email = "contact@ryansobol.com"
10
+ s.homepage = "https://github.com/ryansobol/rack-bouncer"
11
+ s.summary = "A Rack middleware that expels undesirable browsers out of your website."
12
+ s.description = "A Rack middleware that expels undesirable browsers out of your website. This project lovingly extends the rack-noie6 gem."
13
+
14
+ s.required_ruby_version = "~> 1.8.7"
15
+ s.required_rubygems_version = ">= 1.3.7"
16
+ s.rubyforge_project = "rack-bouncer"
17
+
18
+ s.add_development_dependency "minitest", "~> 2.11.1"
19
+ s.add_development_dependency "rack", "~> 1.4.1"
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- spec/*`.split("\n")
23
+ s.require_paths = ["lib"]
24
+ end
@@ -0,0 +1,264 @@
1
+ # encoding: UTF-8
2
+ require "rubygems"
3
+ require "minitest/autorun"
4
+ require "rack/mock"
5
+
6
+ require "rack/bouncer"
7
+
8
+ class TestApp
9
+ def call(env)
10
+ [200, {}, "Hi Internets!"]
11
+ end
12
+ end
13
+
14
+ def create_request(options = {})
15
+ Rack::MockRequest.new(Rack::Bouncer.new(TestApp.new, options))
16
+ end
17
+
18
+ class Rack::Bouncer::Test < MiniTest::Unit::TestCase
19
+
20
+ def test_version
21
+ assert_equal "1.2", Rack::Bouncer::VERSION
22
+ end
23
+
24
+ def test_default_safe_paths
25
+ expected = ["/assets", "/images", "/stylesheets", "/javascripts", "/feedback"]
26
+ assert_equal expected, Rack::Bouncer::DEFAULT_OPTIONS[:safe_paths]
27
+ end
28
+
29
+ def test_default_redirect
30
+ assert_equal "http://browsehappy.com/", Rack::Bouncer::DEFAULT_OPTIONS[:redirect]
31
+ end
32
+
33
+ def test_default_minimum_ie
34
+ assert_equal 8.0, Rack::Bouncer::DEFAULT_OPTIONS[:minimum_ie]
35
+ end
36
+
37
+ def test_allows_if_no_user_agent_specified
38
+ request = create_request
39
+ response = request.get("/")
40
+ assert_equal 200, response.status
41
+ assert_equal "Hi Internets!", response.body
42
+ end
43
+
44
+ # Internet Explorer
45
+ #################################################################################################
46
+
47
+ def test_allows_if_not_ie
48
+ request = create_request
49
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/5.0"})
50
+ assert_equal "Hi Internets!", response.body
51
+ end
52
+
53
+ def test_allows_ie_if_no_version_available
54
+ request = create_request
55
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (compatible; MSIE l4me; Windows XP)"})
56
+ assert_equal 200, response.status
57
+ assert_equal "Hi Internets!", response.body
58
+ end
59
+
60
+ def test_expels_ie_6_and_redirects_to_default
61
+ request = create_request
62
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)" })
63
+ assert_equal 302, response.status
64
+ assert_equal response.location, "http://browsehappy.com/"
65
+ end
66
+
67
+ def test_expels_ie_6_and_redirects_to_internal_url
68
+ request = create_request(:redirect => "/foo")
69
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)" })
70
+ assert_equal 302, response.status
71
+ assert_equal response.location, "/foo"
72
+ end
73
+
74
+ def test_expels_ie_6_and_redirects_to_external_url
75
+ request = create_request(:redirect => "http://getfirefox.com")
76
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)" })
77
+ assert_equal 302, response.status
78
+ assert_equal response.location, "http://getfirefox.com"
79
+ end
80
+
81
+ def test_allows_ie_6_when_minimum
82
+ request = create_request(:minimum_ie => 6.0)
83
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)" })
84
+ assert_equal 200, response.status
85
+ assert_equal "Hi Internets!", response.body
86
+ end
87
+
88
+ def test_expels_ie_7
89
+ request = create_request
90
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)" })
91
+ assert_equal 302, response.status
92
+ assert_equal response.location, "http://browsehappy.com/"
93
+ end
94
+
95
+ def test_allows_ie_7_when_minimum
96
+ request = create_request(:minimum_ie => 7.0)
97
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)" })
98
+ assert_equal 200, response.status
99
+ assert_equal "Hi Internets!", response.body
100
+ end
101
+
102
+ def test_allows_ie_8
103
+ request = create_request
104
+ response = request.get("/", {"HTTP_USER_AGENT" => "User-Agent:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)" })
105
+ assert_equal 200, response.status
106
+ assert_equal "Hi Internets!", response.body
107
+ end
108
+
109
+ def test_allows_ie_8_when_minimum
110
+ request = create_request(:minimum_ie => 8.0)
111
+ response = request.get("/", {"HTTP_USER_AGENT" => "User-Agent:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)" })
112
+ assert_equal 200, response.status
113
+ assert_equal "Hi Internets!", response.body
114
+ end
115
+
116
+ def test_allows_ie_9
117
+ request = create_request
118
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;" })
119
+ assert_equal 200, response.status
120
+ assert_equal "Hi Internets!", response.body
121
+ end
122
+
123
+ # AOL
124
+ #################################################################################################
125
+
126
+ def test_expels_aol_6
127
+ request = create_request
128
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (compatible; MSIE 5.5; AOL 6.0; Windows 98)" })
129
+ assert_equal 302, response.status
130
+ assert_equal response.location, "http://browsehappy.com/"
131
+ end
132
+
133
+ def test_expels_aol_7
134
+ request = create_request
135
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (compatible; MSIE 7.0; AOL 7.0; Windows NT 5.1)" })
136
+ assert_equal 302, response.status
137
+ assert_equal response.location, "http://browsehappy.com/"
138
+ end
139
+
140
+ def test_expels_aol_8
141
+ request = create_request
142
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (compatible; MSIE 7.0; AOL 8.0; Windows NT 5.1)" })
143
+ assert_equal 302, response.status
144
+ assert_equal response.location, "http://browsehappy.com/"
145
+ end
146
+
147
+ def test_expels_aol_9
148
+ request = create_request
149
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.0; Windows NT 5.1)" })
150
+ assert_equal 302, response.status
151
+ assert_equal response.location, "http://browsehappy.com/"
152
+ end
153
+
154
+ def test_expels_aol_9_1
155
+ request = create_request
156
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.1; AOLBuild 4334.5000; Windows NT 5.1; Trident/4.0)" })
157
+ assert_equal 302, response.status
158
+ assert_equal response.location, "http://browsehappy.com/"
159
+ end
160
+
161
+ def test_expels_aol_9_5
162
+ request = create_request
163
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.43; Windows NT 5.1; Trident/4.0)" })
164
+ assert_equal 302, response.status
165
+ assert_equal response.location, "http://browsehappy.com/"
166
+ end
167
+
168
+ def test_expels_aol_9_6
169
+ request = create_request
170
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/4.0 (compatible; MSIE 8.0; AOL 9.6; AOLBuild 4340.5004; Windows NT 5.1; Trident/4.0)" })
171
+ assert_equal 302, response.status
172
+ assert_equal response.location, "http://browsehappy.com/"
173
+ end
174
+
175
+ # Firefox
176
+ #################################################################################################
177
+
178
+ def test_allows_firefox_4
179
+ request = create_request
180
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0" })
181
+ assert_equal 200, response.status
182
+ assert_equal "Hi Internets!", response.body
183
+ end
184
+
185
+ # Safari
186
+ #################################################################################################
187
+
188
+ def test_allows_safari_5_0
189
+ request = create_request
190
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0 Safari/533.16" })
191
+ assert_equal 200, response.status
192
+ assert_equal "Hi Internets!", response.body
193
+ end
194
+
195
+ def test_allows_safari_5_1
196
+ request = create_request
197
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.52.7 (KHTML, like Gecko) Version/5.1 Safari/534.52.7" })
198
+ assert_equal 200, response.status
199
+ assert_equal "Hi Internets!", response.body
200
+ end
201
+
202
+ # Chrome
203
+ #################################################################################################
204
+
205
+ def test_allows_chrome_16
206
+ request = create_request
207
+ response = request.get("/", {"HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.77 Safari/535.7" })
208
+ assert_equal 200, response.status
209
+ assert_equal "Hi Internets!", response.body
210
+ end
211
+
212
+ # Safe Paths
213
+ #################################################################################################
214
+
215
+ def test_allows_redirect_path
216
+ request = create_request(:redirect => "/browser")
217
+ response = request.get("/browser", {"HTTP_USER_AGENT" => "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)" })
218
+ assert_equal 200, response.status
219
+ assert_equal "Hi Internets!", response.body
220
+ end
221
+
222
+ def test_expels_non_redirect_path
223
+ request = create_request(:redirect => "/browser")
224
+ response = request.get("/wrong", {"HTTP_USER_AGENT" => "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)" })
225
+ assert_equal 302, response.status
226
+ assert_equal response.location, "/browser"
227
+ end
228
+
229
+ def test_allows_assets_path
230
+ request = create_request
231
+ response = request.get("/assets", {"HTTP_USER_AGENT" => "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)" })
232
+ assert_equal 200, response.status
233
+ assert_equal "Hi Internets!", response.body
234
+ end
235
+
236
+ def test_allows_images_path
237
+ request = create_request
238
+ response = request.get("/images", {"HTTP_USER_AGENT" => "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)" })
239
+ assert_equal 200, response.status
240
+ assert_equal "Hi Internets!", response.body
241
+ end
242
+
243
+ def test_allows_stylesheets_path
244
+ request = create_request
245
+ response = request.get("/stylesheets", {"HTTP_USER_AGENT" => "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)" })
246
+ assert_equal 200, response.status
247
+ assert_equal "Hi Internets!", response.body
248
+ end
249
+
250
+ def test_allows_javascripts_path
251
+ request = create_request
252
+ response = request.get("/javascripts", {"HTTP_USER_AGENT" => "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)" })
253
+ assert_equal 200, response.status
254
+ assert_equal "Hi Internets!", response.body
255
+ end
256
+
257
+ def test_allows_feedback_path
258
+ request = create_request
259
+ response = request.get("/feedback", {"HTTP_USER_AGENT" => "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)" })
260
+ assert_equal 200, response.status
261
+ assert_equal "Hi Internets!", response.body
262
+ end
263
+
264
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-bouncer
3
+ version: !ruby/object:Gem::Version
4
+ hash: 11
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 2
9
+ version: "1.2"
10
+ platform: ruby
11
+ authors:
12
+ - Jerod Santo
13
+ - Julio Cesar Ody
14
+ - Will Jessop
15
+ - Ryan Sobol
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2012-02-08 00:00:00 -08:00
21
+ default_executable:
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
24
+ name: minitest
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ~>
30
+ - !ruby/object:Gem::Version
31
+ hash: 33
32
+ segments:
33
+ - 2
34
+ - 11
35
+ - 1
36
+ version: 2.11.1
37
+ type: :development
38
+ version_requirements: *id001
39
+ - !ruby/object:Gem::Dependency
40
+ name: rack
41
+ prerelease: false
42
+ requirement: &id002 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ hash: 5
48
+ segments:
49
+ - 1
50
+ - 4
51
+ - 1
52
+ version: 1.4.1
53
+ type: :development
54
+ version_requirements: *id002
55
+ description: A Rack middleware that expels undesirable browsers out of your website. This project lovingly extends the rack-noie6 gem.
56
+ email: contact@ryansobol.com
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files: []
62
+
63
+ files:
64
+ - .gitignore
65
+ - .rvmrc
66
+ - Gemfile
67
+ - Gemfile.lock
68
+ - README.md
69
+ - Rakefile
70
+ - lib/rack/bouncer.rb
71
+ - rack-bouncer.gemspec
72
+ - test/lib/rack/bouncer_test.rb
73
+ has_rdoc: true
74
+ homepage: https://github.com/ryansobol/rack-bouncer
75
+ licenses: []
76
+
77
+ post_install_message:
78
+ rdoc_options: []
79
+
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ hash: 57
88
+ segments:
89
+ - 1
90
+ - 8
91
+ - 7
92
+ version: 1.8.7
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 21
99
+ segments:
100
+ - 1
101
+ - 3
102
+ - 7
103
+ version: 1.3.7
104
+ requirements: []
105
+
106
+ rubyforge_project: rack-bouncer
107
+ rubygems_version: 1.6.2
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: A Rack middleware that expels undesirable browsers out of your website.
111
+ test_files: []
112
+