rack-bouncer 1.3.1 → 1.4.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/README.md +33 -7
- data/lib/rack/bouncer.rb +41 -38
- data/test/lib/rack/bouncer/aol_test.rb +15 -8
- data/test/lib/rack/bouncer/chrome_test.rb +93 -2
- data/test/lib/rack/bouncer/firefox_test.rb +15 -8
- data/test/lib/rack/bouncer/ie_test.rb +21 -35
- data/test/lib/rack/bouncer/safari_test.rb +105 -0
- data/test/lib/rack/bouncer_test.rb +49 -10
- data/test/user_agents.yml +66 -14
- metadata +4 -4
data/README.md
CHANGED
@@ -4,9 +4,11 @@ A Rack middleware that expels undesirable browsers out of your website. This pro
|
|
4
4
|
|
5
5
|
| _Browser_ | _Undesirable Versions_ |
|
6
6
|
|-------------------|------------------------|
|
7
|
-
| Internet Explorer | < 8.0 |
|
8
|
-
| Firefox | < 4.0 |
|
9
7
|
| AOL | All |
|
8
|
+
| Chrome | < 7.0 |
|
9
|
+
| Firefox | < 4.0 |
|
10
|
+
| Internet Explorer | < 8.0 |
|
11
|
+
| Safari | < 4.0 |
|
10
12
|
|
11
13
|
## usage
|
12
14
|
|
@@ -19,19 +21,27 @@ The default redirects users to [Browse Happy](http://browsehappy.com/):
|
|
19
21
|
|
20
22
|
You can redirect users to a page in your website:
|
21
23
|
|
22
|
-
use Rack::Bouncer, :redirect => "/
|
24
|
+
use Rack::Bouncer, :redirect => "/requirements.html"
|
23
25
|
|
24
26
|
You can redirect users to a URL as well:
|
25
27
|
|
26
|
-
use Rack::Bouncer, :redirect => "
|
28
|
+
use Rack::Bouncer, :redirect => "https://www.google.com/chrome"
|
27
29
|
|
28
|
-
You can specify a minimum version of
|
30
|
+
You can specify a minimum version of Chrome like so:
|
29
31
|
|
30
|
-
use Rack::Bouncer, :
|
32
|
+
use Rack::Bouncer, :minimum_firefox => 6.0
|
31
33
|
|
32
34
|
You can specify a minimum version of Firefox like so:
|
33
35
|
|
34
|
-
use Rack::Bouncer, :
|
36
|
+
use Rack::Bouncer, :minimum_firefox => 3.6
|
37
|
+
|
38
|
+
You can specify a minimum version of IE like so:
|
39
|
+
|
40
|
+
use Rack::Bouncer, :minimum_ie => 6.0
|
41
|
+
|
42
|
+
You can specify a minimum version of Safari like so:
|
43
|
+
|
44
|
+
use Rack::Bouncer, :minimum_safari => 3.0
|
35
45
|
|
36
46
|
You can specify a set of safe paths:
|
37
47
|
|
@@ -39,6 +49,22 @@ You can specify a set of safe paths:
|
|
39
49
|
|
40
50
|
*NOTE:* By default, the above paths are safe already.
|
41
51
|
|
52
|
+
## warning
|
53
|
+
|
54
|
+
I use this gem in a production Rails app and it works great. But in development, my app throws the following error whenever the `Rack::Bouncer` middleware is triggered:
|
55
|
+
|
56
|
+
!! Unexpected error while processing request: thread 0x1001d5258 tried to join itself
|
57
|
+
|
58
|
+
I'm using the following versions of Ruby and Rails:
|
59
|
+
|
60
|
+
$ ruby -v
|
61
|
+
ruby 1.8.7 (2011-02-18 patchlevel 334) [i686-darwin10.7.0], MBARI 0x6770, Ruby Enterprise Edition 2011.03
|
62
|
+
|
63
|
+
$ rails -v
|
64
|
+
Rails 2.3.14
|
65
|
+
|
66
|
+
If anyone has a suggestion, I'd appreciate your help.
|
67
|
+
|
42
68
|
## contributing
|
43
69
|
|
44
70
|
Pull requests are very welcome. You'd be doing me a favor if you could test cover your enhancement and ensure the test suite passes *before* initiating a pull request.
|
data/lib/rack/bouncer.rb
CHANGED
@@ -2,13 +2,15 @@
|
|
2
2
|
|
3
3
|
module Rack
|
4
4
|
class Bouncer
|
5
|
-
VERSION = "1.
|
5
|
+
VERSION = "1.4.0"
|
6
6
|
|
7
7
|
DEFAULT_OPTIONS = {
|
8
8
|
:safe_paths => ["/asset", "/images", "/stylesheets", "/javascripts", "/feedback"],
|
9
9
|
:redirect => "http://browsehappy.com/",
|
10
|
+
:minimum_chrome => 7.0,
|
11
|
+
:minimum_firefox => 4.0,
|
10
12
|
:minimum_ie => 8.0,
|
11
|
-
:
|
13
|
+
:minimum_safari => 4.0
|
12
14
|
}
|
13
15
|
|
14
16
|
def initialize(app, options = {})
|
@@ -17,16 +19,15 @@ module Rack
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def call(env)
|
20
|
-
return @app.call(env) if safe_path?(env)
|
21
|
-
return @app.call(env) if user_agent_blank?(env)
|
22
|
+
return @app.call(env) if safe_path?(env) || user_agent_blank?(env)
|
22
23
|
|
23
24
|
user_agent = env["HTTP_USER_AGENT"]
|
24
25
|
|
25
|
-
if
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
return expel if undesirable_ie?(user_agent) ||
|
27
|
+
undesirable_aol?(user_agent) ||
|
28
|
+
undesirable_firefox?(user_agent) ||
|
29
|
+
undesirable_safari?(user_agent) ||
|
30
|
+
undesirable_chrome?(user_agent)
|
30
31
|
|
31
32
|
@app.call(env)
|
32
33
|
end
|
@@ -42,51 +43,53 @@ module Rack
|
|
42
43
|
env["HTTP_USER_AGENT"].nil? || env["HTTP_USER_AGENT"].empty?
|
43
44
|
end
|
44
45
|
|
45
|
-
def
|
46
|
-
|
46
|
+
def expel
|
47
|
+
header = { "Location" => @options[:redirect], "Content-Type" => "text/html" }
|
48
|
+
[302, header, "User Agent not permitted"]
|
47
49
|
end
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
+
def undesirable_ie?(user_agent)
|
52
|
+
match = user_agent.match(/MSIE (\S+)/)
|
53
|
+
return false if match.nil?
|
51
54
|
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
+
version = match[1].to_f
|
56
|
+
return false if version == 0.0
|
55
57
|
|
56
|
-
|
57
|
-
# We need at least one digit to be able to get the version, hence the \d
|
58
|
-
user_agent.match(/MSIE \d/) ? true : false
|
58
|
+
version < @options[:minimum_ie]
|
59
59
|
end
|
60
60
|
|
61
|
-
def
|
62
|
-
user_agent.match(/
|
61
|
+
def undesirable_aol?(user_agent)
|
62
|
+
user_agent.match(/AOL \S+/) ? true : false
|
63
63
|
end
|
64
64
|
|
65
|
-
|
66
|
-
|
65
|
+
def undesirable_firefox?(user_agent)
|
66
|
+
match = user_agent.match(/Firefox\/(\S+)/)
|
67
|
+
return false if match.nil?
|
67
68
|
|
68
|
-
|
69
|
-
|
70
|
-
end
|
69
|
+
version = match[1].to_f
|
70
|
+
return false if version == 0.0
|
71
71
|
|
72
|
-
|
73
|
-
user_agent.match(/AOL \d/) ? true : false
|
72
|
+
version < @options[:minimum_firefox]
|
74
73
|
end
|
75
74
|
|
76
|
-
|
77
|
-
|
75
|
+
def undesirable_safari?(user_agent)
|
76
|
+
match = user_agent.match(/Version\/(\S+)\s+Safari\/\S+/)
|
77
|
+
return false if match.nil?
|
78
78
|
|
79
|
-
|
80
|
-
|
81
|
-
end
|
79
|
+
version = match[1].to_f
|
80
|
+
return false if version == 0.0
|
82
81
|
|
83
|
-
|
84
|
-
# We need at least one digit to be able to get the version, hence the \d
|
85
|
-
user_agent.match(/Firefox\/\d/) ? true : false
|
82
|
+
version < @options[:minimum_safari]
|
86
83
|
end
|
87
84
|
|
88
|
-
def
|
89
|
-
user_agent.match(/
|
85
|
+
def undesirable_chrome?(user_agent)
|
86
|
+
match = user_agent.match(/Chrome\/(\S+)\s+Safari\/\S+/)
|
87
|
+
return false if match.nil?
|
88
|
+
|
89
|
+
version = match[1].to_f
|
90
|
+
return false if version == 0.0
|
91
|
+
|
92
|
+
version < @options[:minimum_chrome]
|
90
93
|
end
|
91
94
|
end
|
92
95
|
end
|
@@ -1,30 +1,37 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class Rack::Bouncer::AOLTest < MiniTest::Unit::TestCase
|
4
|
-
def
|
4
|
+
def test_expels_aol_l4me
|
5
5
|
request = create_request
|
6
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
6
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:aol_l4me])
|
7
7
|
assert_equal 302, response.status
|
8
8
|
assert_equal response.location, "http://browsehappy.com/"
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
11
|
+
def test_expels_aol_6_0
|
12
12
|
request = create_request
|
13
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
13
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:aol_6_0])
|
14
14
|
assert_equal 302, response.status
|
15
15
|
assert_equal response.location, "http://browsehappy.com/"
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
18
|
+
def test_expels_aol_7_0
|
19
19
|
request = create_request
|
20
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
20
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:aol_7_0])
|
21
21
|
assert_equal 302, response.status
|
22
22
|
assert_equal response.location, "http://browsehappy.com/"
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
25
|
+
def test_expels_aol_8_0
|
26
26
|
request = create_request
|
27
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
27
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:aol_8_0])
|
28
|
+
assert_equal 302, response.status
|
29
|
+
assert_equal response.location, "http://browsehappy.com/"
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_expels_aol_9_0
|
33
|
+
request = create_request
|
34
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:aol_9_0])
|
28
35
|
assert_equal 302, response.status
|
29
36
|
assert_equal response.location, "http://browsehappy.com/"
|
30
37
|
end
|
@@ -1,9 +1,100 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class Rack::Bouncer::ChromeTest < MiniTest::Unit::TestCase
|
4
|
-
def
|
4
|
+
def test_allows_chrome_l4me
|
5
5
|
request = create_request
|
6
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
6
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_l4me])
|
7
|
+
assert_equal 200, response.status
|
8
|
+
assert_equal "Hi Internets!", response.body
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_expels_chrome_6_0
|
12
|
+
request = create_request
|
13
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_6_0])
|
14
|
+
assert_equal 302, response.status
|
15
|
+
assert_equal response.location, "http://browsehappy.com/"
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_allows_chrome_6_0_when_minimum
|
19
|
+
request = create_request(:minimum_chrome => 6.0)
|
20
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_6_0])
|
21
|
+
assert_equal 200, response.status
|
22
|
+
assert_equal "Hi Internets!", response.body
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_allows_chrome_7_0
|
26
|
+
request = create_request
|
27
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_7_0])
|
28
|
+
assert_equal 200, response.status
|
29
|
+
assert_equal "Hi Internets!", response.body
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_allows_chrome_8_0
|
33
|
+
request = create_request
|
34
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_8_0])
|
35
|
+
assert_equal 200, response.status
|
36
|
+
assert_equal "Hi Internets!", response.body
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_allows_chrome_9_0
|
40
|
+
request = create_request
|
41
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_9_0])
|
42
|
+
assert_equal 200, response.status
|
43
|
+
assert_equal "Hi Internets!", response.body
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_allows_chrome_10_0
|
47
|
+
request = create_request
|
48
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_10_0])
|
49
|
+
assert_equal 200, response.status
|
50
|
+
assert_equal "Hi Internets!", response.body
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_allows_chrome_11_0
|
54
|
+
request = create_request
|
55
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_11_0])
|
56
|
+
assert_equal 200, response.status
|
57
|
+
assert_equal "Hi Internets!", response.body
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_allows_chrome_12_0
|
61
|
+
request = create_request
|
62
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_12_0])
|
63
|
+
assert_equal 200, response.status
|
64
|
+
assert_equal "Hi Internets!", response.body
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_allows_chrome_13_0
|
68
|
+
request = create_request
|
69
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_13_0])
|
70
|
+
assert_equal 200, response.status
|
71
|
+
assert_equal "Hi Internets!", response.body
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_allows_chrome_14_0
|
75
|
+
request = create_request
|
76
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_14_0])
|
77
|
+
assert_equal 200, response.status
|
78
|
+
assert_equal "Hi Internets!", response.body
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_allows_chrome_15_0
|
82
|
+
request = create_request
|
83
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_15_0])
|
84
|
+
assert_equal 200, response.status
|
85
|
+
assert_equal "Hi Internets!", response.body
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_allows_chrome_16_0
|
89
|
+
request = create_request
|
90
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_16_0])
|
91
|
+
assert_equal 200, response.status
|
92
|
+
assert_equal "Hi Internets!", response.body
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_allows_chrome_17_0
|
96
|
+
request = create_request
|
97
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:chrome_17_0])
|
7
98
|
assert_equal 200, response.status
|
8
99
|
assert_equal "Hi Internets!", response.body
|
9
100
|
end
|
@@ -1,6 +1,13 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class Rack::Bouncer::FirefoxTest < MiniTest::Unit::TestCase
|
4
|
+
def test_allows_firefox_l4me
|
5
|
+
request = create_request
|
6
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:firefox_l4me])
|
7
|
+
assert_equal 200, response.status
|
8
|
+
assert_equal "Hi Internets!", response.body
|
9
|
+
end
|
10
|
+
|
4
11
|
def test_expels_firefox_3_6
|
5
12
|
request = create_request
|
6
13
|
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:firefox_3_6])
|
@@ -43,9 +50,9 @@ class Rack::Bouncer::FirefoxTest < MiniTest::Unit::TestCase
|
|
43
50
|
assert_equal response.location, "http://browsehappy.com/"
|
44
51
|
end
|
45
52
|
|
46
|
-
def
|
53
|
+
def test_allows_firefox_4_0
|
47
54
|
request = create_request
|
48
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
55
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:firefox_4_0])
|
49
56
|
assert_equal 200, response.status
|
50
57
|
assert_equal "Hi Internets!", response.body
|
51
58
|
end
|
@@ -57,23 +64,23 @@ class Rack::Bouncer::FirefoxTest < MiniTest::Unit::TestCase
|
|
57
64
|
assert_equal "Hi Internets!", response.body
|
58
65
|
end
|
59
66
|
|
60
|
-
def
|
67
|
+
def test_allows_firefox_5_0
|
61
68
|
request = create_request
|
62
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
69
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:firefox_5_0])
|
63
70
|
assert_equal 200, response.status
|
64
71
|
assert_equal "Hi Internets!", response.body
|
65
72
|
end
|
66
73
|
|
67
|
-
def
|
74
|
+
def test_allows_firefox_6_0
|
68
75
|
request = create_request
|
69
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
76
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:firefox_6_0])
|
70
77
|
assert_equal 200, response.status
|
71
78
|
assert_equal "Hi Internets!", response.body
|
72
79
|
end
|
73
80
|
|
74
|
-
def
|
81
|
+
def test_allows_firefox_9_0
|
75
82
|
request = create_request
|
76
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
83
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:firefox_9_0])
|
77
84
|
assert_equal 200, response.status
|
78
85
|
assert_equal "Hi Internets!", response.body
|
79
86
|
end
|
@@ -1,72 +1,58 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class Rack::Bouncer::IETest < MiniTest::Unit::TestCase
|
4
|
-
def
|
4
|
+
def test_allows_ie_l4me
|
5
5
|
request = create_request
|
6
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
6
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_l4me])
|
7
7
|
assert_equal 200, response.status
|
8
8
|
assert_equal "Hi Internets!", response.body
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
request = create_request
|
13
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6])
|
14
|
-
assert_equal 302, response.status
|
15
|
-
assert_equal response.location, "http://browsehappy.com/"
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_expels_ie_6_and_redirects_to_internal_url
|
19
|
-
request = create_request(:redirect => "/foo")
|
20
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6])
|
21
|
-
assert_equal 302, response.status
|
22
|
-
assert_equal response.location, "/foo"
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_expels_ie_6_and_redirects_to_external_url
|
26
|
-
request = create_request(:redirect => "http://getfirefox.com")
|
27
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6])
|
28
|
-
assert_equal 302, response.status
|
29
|
-
assert_equal response.location, "http://getfirefox.com"
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_allows_ie_6_when_minimum
|
11
|
+
def test_allows_ie_6_0_when_minimum
|
33
12
|
request = create_request(:minimum_ie => 6.0)
|
34
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
13
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6_0])
|
35
14
|
assert_equal 200, response.status
|
36
15
|
assert_equal "Hi Internets!", response.body
|
37
16
|
end
|
38
17
|
|
39
|
-
def
|
18
|
+
def test_expels_ie_7_0
|
19
|
+
request = create_request
|
20
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_7_0])
|
21
|
+
assert_equal 302, response.status
|
22
|
+
assert_equal response.location, "http://browsehappy.com/"
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_expels_ie_7_0_b
|
40
26
|
request = create_request
|
41
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
27
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_7_0_b])
|
42
28
|
assert_equal 302, response.status
|
43
29
|
assert_equal response.location, "http://browsehappy.com/"
|
44
30
|
end
|
45
31
|
|
46
|
-
def
|
32
|
+
def test_allows_ie_7_0_when_minimum
|
47
33
|
request = create_request(:minimum_ie => 7.0)
|
48
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
34
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_7_0])
|
49
35
|
assert_equal 200, response.status
|
50
36
|
assert_equal "Hi Internets!", response.body
|
51
37
|
end
|
52
38
|
|
53
|
-
def
|
39
|
+
def test_allows_ie_8_0
|
54
40
|
request = create_request
|
55
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
41
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_8_0])
|
56
42
|
assert_equal 200, response.status
|
57
43
|
assert_equal "Hi Internets!", response.body
|
58
44
|
end
|
59
45
|
|
60
|
-
def
|
46
|
+
def test_allows_ie_8_0_when_minimum
|
61
47
|
request = create_request(:minimum_ie => 8.0)
|
62
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
48
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_8_0])
|
63
49
|
assert_equal 200, response.status
|
64
50
|
assert_equal "Hi Internets!", response.body
|
65
51
|
end
|
66
52
|
|
67
|
-
def
|
53
|
+
def test_allows_ie_9_0
|
68
54
|
request = create_request
|
69
|
-
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:
|
55
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_9_0])
|
70
56
|
assert_equal 200, response.status
|
71
57
|
assert_equal "Hi Internets!", response.body
|
72
58
|
end
|
@@ -1,6 +1,97 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class Rack::Bouncer::SafariTest < MiniTest::Unit::TestCase
|
4
|
+
def test_allows_safari_l4me
|
5
|
+
request = create_request
|
6
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_l4me])
|
7
|
+
assert_equal 200, response.status
|
8
|
+
assert_equal "Hi Internets!", response.body
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_expels_safari_3_0
|
12
|
+
request = create_request
|
13
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_3_0])
|
14
|
+
assert_equal 302, response.status
|
15
|
+
assert_equal response.location, "http://browsehappy.com/"
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_allows_safari_3_0_when_minimum
|
19
|
+
request = create_request(:minimum_safari => 3.0)
|
20
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_3_0])
|
21
|
+
assert_equal 200, response.status
|
22
|
+
assert_equal "Hi Internets!", response.body
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_expels_safari_3_0_1
|
26
|
+
request = create_request
|
27
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_3_0_1])
|
28
|
+
assert_equal 302, response.status
|
29
|
+
assert_equal response.location, "http://browsehappy.com/"
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_allows_safari_3_0_1_when_minimum
|
33
|
+
request = create_request(:minimum_safari => 3.0)
|
34
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_3_0_1])
|
35
|
+
assert_equal 200, response.status
|
36
|
+
assert_equal "Hi Internets!", response.body
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_expels_safari_3_1
|
40
|
+
request = create_request
|
41
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_3_1])
|
42
|
+
assert_equal 302, response.status
|
43
|
+
assert_equal response.location, "http://browsehappy.com/"
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_allows_safari_3_1_when_minimum
|
47
|
+
request = create_request(:minimum_safari => 3.1)
|
48
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_3_1])
|
49
|
+
assert_equal 200, response.status
|
50
|
+
assert_equal "Hi Internets!", response.body
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_expels_safari_3_1_2
|
54
|
+
request = create_request
|
55
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_3_1_2])
|
56
|
+
assert_equal 302, response.status
|
57
|
+
assert_equal response.location, "http://browsehappy.com/"
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_allows_safari_3_1_2_when_minimum
|
61
|
+
request = create_request(:minimum_safari => 3.1)
|
62
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_3_1_2])
|
63
|
+
assert_equal 200, response.status
|
64
|
+
assert_equal "Hi Internets!", response.body
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_allows_safari_4_0
|
68
|
+
request = create_request
|
69
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_4_0])
|
70
|
+
assert_equal 200, response.status
|
71
|
+
assert_equal "Hi Internets!", response.body
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_allows_safari_4_0_1
|
75
|
+
request = create_request
|
76
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_4_0_1])
|
77
|
+
assert_equal 200, response.status
|
78
|
+
assert_equal "Hi Internets!", response.body
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_allows_safari_4_0_dp1
|
82
|
+
request = create_request
|
83
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_4_0_dp1])
|
84
|
+
assert_equal 200, response.status
|
85
|
+
assert_equal "Hi Internets!", response.body
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_allows_safari_4_1
|
89
|
+
request = create_request
|
90
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_4_1])
|
91
|
+
assert_equal 200, response.status
|
92
|
+
assert_equal "Hi Internets!", response.body
|
93
|
+
end
|
94
|
+
|
4
95
|
def test_allows_safari_5_0
|
5
96
|
request = create_request
|
6
97
|
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_5_0])
|
@@ -8,10 +99,24 @@ class Rack::Bouncer::SafariTest < MiniTest::Unit::TestCase
|
|
8
99
|
assert_equal "Hi Internets!", response.body
|
9
100
|
end
|
10
101
|
|
102
|
+
def test_allows_safari_5_0_1
|
103
|
+
request = create_request
|
104
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_5_0_1])
|
105
|
+
assert_equal 200, response.status
|
106
|
+
assert_equal "Hi Internets!", response.body
|
107
|
+
end
|
108
|
+
|
11
109
|
def test_allows_safari_5_1
|
12
110
|
request = create_request
|
13
111
|
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_5_1])
|
14
112
|
assert_equal 200, response.status
|
15
113
|
assert_equal "Hi Internets!", response.body
|
16
114
|
end
|
115
|
+
|
116
|
+
def test_allows_safari_5_1_2
|
117
|
+
request = create_request
|
118
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:safari_5_1_2])
|
119
|
+
assert_equal 200, response.status
|
120
|
+
assert_equal "Hi Internets!", response.body
|
121
|
+
end
|
17
122
|
end
|
@@ -3,9 +3,12 @@ require "test_helper"
|
|
3
3
|
|
4
4
|
class Rack::BouncerTest < MiniTest::Unit::TestCase
|
5
5
|
def test_version
|
6
|
-
assert_equal "1.
|
6
|
+
assert_equal "1.4.0", Rack::Bouncer::VERSION
|
7
7
|
end
|
8
8
|
|
9
|
+
# Default Options
|
10
|
+
#################################################################################################
|
11
|
+
|
9
12
|
def test_default_safe_paths
|
10
13
|
expected = ["/asset", "/images", "/stylesheets", "/javascripts", "/feedback"]
|
11
14
|
assert_equal expected, Rack::Bouncer::DEFAULT_OPTIONS[:safe_paths]
|
@@ -15,14 +18,25 @@ class Rack::BouncerTest < MiniTest::Unit::TestCase
|
|
15
18
|
assert_equal "http://browsehappy.com/", Rack::Bouncer::DEFAULT_OPTIONS[:redirect]
|
16
19
|
end
|
17
20
|
|
18
|
-
def
|
19
|
-
assert_equal
|
21
|
+
def test_default_minimum_chrome
|
22
|
+
assert_equal 7.0, Rack::Bouncer::DEFAULT_OPTIONS[:minimum_chrome]
|
20
23
|
end
|
21
24
|
|
22
25
|
def test_default_minimum_firefox
|
23
26
|
assert_equal 4.0, Rack::Bouncer::DEFAULT_OPTIONS[:minimum_firefox]
|
24
27
|
end
|
25
28
|
|
29
|
+
def test_default_minimum_ie
|
30
|
+
assert_equal 8.0, Rack::Bouncer::DEFAULT_OPTIONS[:minimum_ie]
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_default_minimum_safari
|
34
|
+
assert_equal 4.0, Rack::Bouncer::DEFAULT_OPTIONS[:minimum_safari]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Edge Cases
|
38
|
+
#################################################################################################
|
39
|
+
|
26
40
|
def test_allows_if_no_user_agent_specified
|
27
41
|
request = create_request
|
28
42
|
response = request.get("/")
|
@@ -37,54 +51,79 @@ class Rack::BouncerTest < MiniTest::Unit::TestCase
|
|
37
51
|
assert_equal "Hi Internets!", response.body
|
38
52
|
end
|
39
53
|
|
54
|
+
# Redirects
|
55
|
+
#################################################################################################
|
56
|
+
|
57
|
+
def test_redirects_to_default
|
58
|
+
request = create_request
|
59
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6_0])
|
60
|
+
assert_equal 302, response.status
|
61
|
+
assert_equal response.location, "http://browsehappy.com/"
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_redirects_to_internal_url
|
65
|
+
request = create_request(:redirect => "/foo")
|
66
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6_0])
|
67
|
+
assert_equal 302, response.status
|
68
|
+
assert_equal response.location, "/foo"
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_redirects_to_external_url
|
72
|
+
request = create_request(:redirect => "https://www.google.com/chrome")
|
73
|
+
response = request.get("/", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6_0])
|
74
|
+
assert_equal 302, response.status
|
75
|
+
assert_equal response.location, "https://www.google.com/chrome"
|
76
|
+
end
|
77
|
+
|
78
|
+
|
40
79
|
# Safe Paths
|
41
80
|
#################################################################################################
|
42
81
|
|
43
82
|
def test_allows_redirect_path
|
44
83
|
request = create_request(:redirect => "/browser")
|
45
|
-
response = request.get("/browser", "HTTP_USER_AGENT" => USER_AGENTS[:
|
84
|
+
response = request.get("/browser", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6_0])
|
46
85
|
assert_equal 200, response.status
|
47
86
|
assert_equal "Hi Internets!", response.body
|
48
87
|
end
|
49
88
|
|
50
89
|
def test_expels_non_redirect_path
|
51
90
|
request = create_request(:redirect => "/browser")
|
52
|
-
response = request.get("/wrong", "HTTP_USER_AGENT" => USER_AGENTS[:
|
91
|
+
response = request.get("/wrong", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6_0])
|
53
92
|
assert_equal 302, response.status
|
54
93
|
assert_equal response.location, "/browser"
|
55
94
|
end
|
56
95
|
|
57
96
|
def test_allows_assets_path
|
58
97
|
request = create_request
|
59
|
-
response = request.get("/asset", "HTTP_USER_AGENT" => USER_AGENTS[:
|
98
|
+
response = request.get("/asset", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6_0])
|
60
99
|
assert_equal 200, response.status
|
61
100
|
assert_equal "Hi Internets!", response.body
|
62
101
|
end
|
63
102
|
|
64
103
|
def test_allows_images_path
|
65
104
|
request = create_request
|
66
|
-
response = request.get("/images", "HTTP_USER_AGENT" => USER_AGENTS[:
|
105
|
+
response = request.get("/images", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6_0])
|
67
106
|
assert_equal 200, response.status
|
68
107
|
assert_equal "Hi Internets!", response.body
|
69
108
|
end
|
70
109
|
|
71
110
|
def test_allows_stylesheets_path
|
72
111
|
request = create_request
|
73
|
-
response = request.get("/stylesheets", "HTTP_USER_AGENT" => USER_AGENTS[:
|
112
|
+
response = request.get("/stylesheets", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6_0])
|
74
113
|
assert_equal 200, response.status
|
75
114
|
assert_equal "Hi Internets!", response.body
|
76
115
|
end
|
77
116
|
|
78
117
|
def test_allows_javascripts_path
|
79
118
|
request = create_request
|
80
|
-
response = request.get("/javascripts", "HTTP_USER_AGENT" => USER_AGENTS[:
|
119
|
+
response = request.get("/javascripts", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6_0])
|
81
120
|
assert_equal 200, response.status
|
82
121
|
assert_equal "Hi Internets!", response.body
|
83
122
|
end
|
84
123
|
|
85
124
|
def test_allows_feedback_path
|
86
125
|
request = create_request
|
87
|
-
response = request.get("/feedback", "HTTP_USER_AGENT" => USER_AGENTS[:
|
126
|
+
response = request.get("/feedback", "HTTP_USER_AGENT" => USER_AGENTS[:ie_6_0])
|
88
127
|
assert_equal 200, response.status
|
89
128
|
assert_equal "Hi Internets!", response.body
|
90
129
|
end
|
data/test/user_agents.yml
CHANGED
@@ -3,13 +3,15 @@
|
|
3
3
|
# AOL
|
4
4
|
###################################################################################################
|
5
5
|
|
6
|
-
:
|
6
|
+
:aol_l4me:
|
7
|
+
Mozilla/4.0 (compatible; MSIE 5.5; AOL l4me; Windows 98)
|
8
|
+
:aol_6_0:
|
7
9
|
Mozilla/4.0 (compatible; MSIE 5.5; AOL 6.0; Windows 98)
|
8
|
-
:
|
10
|
+
:aol_7_0:
|
9
11
|
Mozilla/4.0 (compatible; MSIE 7.0; AOL 7.0; Windows NT 5.1)
|
10
|
-
:
|
12
|
+
:aol_8_0:
|
11
13
|
Mozilla/4.0 (compatible; MSIE 7.0; AOL 8.0; Windows NT 5.1)
|
12
|
-
:
|
14
|
+
:aol_9_0:
|
13
15
|
Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.0; Windows NT 5.1)
|
14
16
|
:aol_9_1:
|
15
17
|
Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.1; AOLBuild 4334.5000; Windows NT 5.1; Trident/4.0)
|
@@ -21,12 +23,38 @@
|
|
21
23
|
# Chrome
|
22
24
|
###################################################################################################
|
23
25
|
|
24
|
-
:
|
26
|
+
:chrome_l4me:
|
27
|
+
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/l4me Safari/535.7
|
28
|
+
:chrome_6_0:
|
29
|
+
Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Chrome/6.0.416.0 Safari/534.1
|
30
|
+
:chrome_7_0:
|
31
|
+
Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.24 Safari/534.7
|
32
|
+
:chrome_8_0:
|
33
|
+
Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.551.0 Safari/534.10
|
34
|
+
:chrome_9_0:
|
35
|
+
Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.44 Safari/534.13
|
36
|
+
:chrome_10_0:
|
37
|
+
Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.15 (KHTML, like Gecko) Chrome/10.0.612.1 Safari/534.15
|
38
|
+
:chrome_11_0:
|
39
|
+
Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/11.0.655.0 Safari/534.17
|
40
|
+
:chrome_12_0:
|
41
|
+
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.53 Safari/534.30
|
42
|
+
:chrome_13_0:
|
43
|
+
Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1
|
44
|
+
:chrome_14_0:
|
45
|
+
Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.792.0 Safari/535.1
|
46
|
+
:chrome_15_0:
|
47
|
+
Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.872.0 Safari/535.2
|
48
|
+
:chrome_16_0:
|
25
49
|
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
|
50
|
+
:chrome_17_0:
|
51
|
+
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.46 Safari/535.11
|
26
52
|
|
27
53
|
# Firefox
|
28
54
|
###################################################################################################
|
29
55
|
|
56
|
+
:firefox_l4me:
|
57
|
+
Mozilla/5.0(Windows; U; Windows NT 5.2; rv:1.9.2) Gecko/20100101 Firefox/l4me
|
30
58
|
:firefox_3_6:
|
31
59
|
Mozilla/5.0(Windows; U; Windows NT 5.2; rv:1.9.2) Gecko/20100101 Firefox/3.6
|
32
60
|
:firefox_3_6_2:
|
@@ -37,15 +65,15 @@
|
|
37
65
|
Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en-US; rv:1.9.2.22) Gecko/20110902 Firefox/3.6.22
|
38
66
|
:firefox_3_8:
|
39
67
|
Mozilla/5.0 (X11; U; Linux i686; rv:1.9.0.2) Gecko/20121223 Ubuntu/9.25 (jaunty) Firefox/3.8
|
40
|
-
:
|
68
|
+
:firefox_4_0:
|
41
69
|
Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0
|
42
70
|
:firefox_4_0_1:
|
43
71
|
Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20110518 Firefox/4.0.1
|
44
|
-
:
|
72
|
+
:firefox_5_0:
|
45
73
|
Mozilla/5.0 (Windows NT 5.1; U; rv:5.0) Gecko/20100101 Firefox/5.0
|
46
|
-
:
|
74
|
+
:firefox_6_0:
|
47
75
|
Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20110814 Firefox/6.0
|
48
|
-
:
|
76
|
+
:firefox_9_0:
|
49
77
|
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0
|
50
78
|
:firefox_9_0_a2:
|
51
79
|
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0a2) Gecko/20111101 Firefox/9.0a2
|
@@ -55,15 +83,17 @@
|
|
55
83
|
# Internet Explorer
|
56
84
|
###################################################################################################
|
57
85
|
|
58
|
-
:
|
86
|
+
:ie_l4me:
|
59
87
|
Mozilla/4.0 (compatible; MSIE l4me; Windows XP)
|
60
|
-
:
|
88
|
+
:ie_6_0:
|
61
89
|
Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)
|
62
|
-
:
|
90
|
+
:ie_7_0:
|
63
91
|
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)
|
64
|
-
:
|
92
|
+
:ie_7_0_b:
|
93
|
+
Mozilla/4.0(compatible; MSIE 7.0b; Windows NT 6.0)
|
94
|
+
:ie_8_0:
|
65
95
|
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)
|
66
|
-
:
|
96
|
+
:ie_9_0:
|
67
97
|
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
|
68
98
|
|
69
99
|
# Mozilla
|
@@ -75,7 +105,29 @@
|
|
75
105
|
# Safari
|
76
106
|
###################################################################################################
|
77
107
|
|
108
|
+
:safari_l4me:
|
109
|
+
Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/523.15 (KHTML, like Gecko) Version/l4me Safari/523.15
|
110
|
+
:safari_3_0:
|
111
|
+
Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/523.15 (KHTML, like Gecko) Version/3.0 Safari/523.15
|
112
|
+
:safari_3_0_1:
|
113
|
+
Mozilla/5.0 (Windows; U; Windows NT 6.0; fi) AppleWebKit/522.12.1 (KHTML, like Gecko) Version/3.0.1 Safari/522.12.2
|
114
|
+
:safari_3_1:
|
115
|
+
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-us) AppleWebKit/526.1+ (KHTML, like Gecko) Version/3.1 Safari/525.13
|
116
|
+
:safari_3_1_2:
|
117
|
+
Mozilla/5.0 (Windows; U; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.1.2 Safari/525.21
|
118
|
+
:safari_4_0:
|
119
|
+
Mozilla/5.0 (Windows; U; Windows NT 6.0; ja-JP) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16
|
120
|
+
:safari_4_0_1:
|
121
|
+
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/531.2+ (KHTML, like Gecko) Version/4.0.1 Safari/530.18
|
122
|
+
:safari_4_0_dp1:
|
123
|
+
Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; en) AppleWebKit/528.4+ (KHTML, like Gecko) Version/4.0dp1 Safari/526.11.2
|
124
|
+
:safari_4_1:
|
125
|
+
Mozilla/5.0 (Windows; U; Windows NT 5.0; en-en) AppleWebKit/533.16 (KHTML, like Gecko) Version/4.1 Safari/533.16
|
78
126
|
:safari_5_0:
|
79
127
|
Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0 Safari/533.16
|
128
|
+
:safari_5_0_1:
|
129
|
+
Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/533.17.8 (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8
|
80
130
|
:safari_5_1:
|
81
131
|
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
|
132
|
+
:safari_5_1_2:
|
133
|
+
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.52.7 (KHTML, like Gecko) Version/5.1.2 Safari/534.52.7
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-bouncer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 1.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Julio Cesar Ody
|