rack-block 0.0.1.pre1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  pkg/*
4
4
  *~
5
5
  .rvmrc
6
+ *\#*
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ # http://about.travis-ci.org/docs/user/build-configuration/
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3-p0
6
+ notifications:
7
+ email:
8
+ - udzura@udzura.jp
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rack-block (0.0.1)
4
+ rack-block (0.0.1.pre1)
5
5
  rack (>= 1.3)
6
6
 
7
7
  GEM
@@ -13,8 +13,11 @@ GEM
13
13
  guard-rspec (0.5.9)
14
14
  guard (>= 0.8.4)
15
15
  rack (1.3.5)
16
+ rack-protection (1.1.4)
17
+ rack
16
18
  rack-test (0.6.1)
17
19
  rack (>= 1.0)
20
+ rake (0.9.2.2)
18
21
  rspec (2.7.0)
19
22
  rspec-core (~> 2.7.0)
20
23
  rspec-expectations (~> 2.7.0)
@@ -23,7 +26,12 @@ GEM
23
26
  rspec-expectations (2.7.0)
24
27
  diff-lcs (~> 1.1.2)
25
28
  rspec-mocks (2.7.0)
29
+ sinatra (1.3.1)
30
+ rack (~> 1.3, >= 1.3.4)
31
+ rack-protection (~> 1.1, >= 1.1.2)
32
+ tilt (~> 1.3, >= 1.3.3)
26
33
  thor (0.14.6)
34
+ tilt (1.3.3)
27
35
 
28
36
  PLATFORMS
29
37
  ruby
@@ -32,4 +40,6 @@ DEPENDENCIES
32
40
  guard-rspec
33
41
  rack-block!
34
42
  rack-test (> 0)
43
+ rake (> 0)
35
44
  rspec (>= 2)
45
+ sinatra (> 1.0)
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2011 Uchio Kondo <udzura@udzura.jp>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
+ software and associated documentation files (the "Software"), to deal in the Software
5
+ without restriction, including without limitation the rights to use, copy, modify, merge,
6
+ publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
+ to whom the Software is furnished to do so, subject to the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all copies or
10
+ substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13
+ BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+
18
+ http://mit-license.org/
data/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # rack-block
2
+
3
+ A rack middleware for controlling accesses by search bot or not, remote ip address, etc.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ $ gem install rack-block
9
+ ```
10
+
11
+ No doubt it depends on `rack` (>= 1.3).
12
+
13
+ ## Usage
14
+
15
+ ### block all bot accesses:
16
+
17
+ ```ruby
18
+ use Rack::Block do
19
+ bot_access do
20
+ halt 404
21
+ end
22
+ end
23
+ run App.new
24
+ ```
25
+
26
+ ### block all bot accesses on a specific path:
27
+
28
+ ```ruby
29
+ use Rack::Block do
30
+ bot_access do
31
+ path '/secret/*' do
32
+ halt 404
33
+ end
34
+ end
35
+ end
36
+ run App.new
37
+ ```
38
+
39
+ ### block some patterns of accesses:
40
+
41
+ ```ruby
42
+ use Rack::Block do
43
+ ua_pattern /googlebot/i do
44
+ halt 404
45
+ end
46
+ end
47
+ run App.new
48
+ ```
49
+
50
+ ### block accesses from specific IP(s):
51
+
52
+ ```ruby
53
+ use Rack::Block do
54
+ ip_pattern '192.0.0.0' do
55
+ # expressions like '192.0.0.' also available
56
+ halt 404
57
+ end
58
+ end
59
+ run App.new
60
+ ```
61
+
62
+ ### redirect accesses:
63
+
64
+ ```ruby
65
+ use Rack::Block do
66
+ bot_access do
67
+ path '/secret/*' do
68
+ redirect '/'
69
+ end
70
+ end
71
+ end
72
+ run App.new
73
+ ```
74
+
75
+ ### redirect accesses to a double app:
76
+
77
+ ```ruby
78
+ use Rack::Block do
79
+ bot_access do
80
+ path '/secret/*' do
81
+ double { Dummy.new # is a Rack-compatible app }
82
+ end
83
+ end
84
+ end
85
+ run App.new
86
+ ```
87
+
88
+ More usage on RDoc: [http://rubydoc.info/github/udzura/rack-block/master/frames]
89
+
90
+ Or please look into `spec/*`
91
+
92
+ ## Related Sites
93
+
94
+ * (official)[http://udzura.jp/rack-block]
95
+ * (rubygems.org)[https://rubygems.org/gems/rack-block]
96
+ * (github)[https://github.com/udzura/rack-block]
97
+ * (travis-ci)[http://travis-ci.org/udzura/rack-block] / <img src="https://secure.travis-ci.org/udzura/rack-block.png" alt="build status" />
98
+ * (author's blog)[http://blog.udzura.jp] (Japanese)
99
+
100
+ ## Todo
101
+
102
+ * Make it more DRY
103
+ * More test cases
104
+ * Refactoring internal classes
105
+ * Proxying accesses to another server
106
+ * Passing IP patterns like `'192.0.0.0/24'`...
107
+
108
+ ## Contributing to rack-block
109
+
110
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
111
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
112
+ * Fork the project
113
+ * Start a feature/bugfix branch
114
+ * Commit and push until you are happy with your contribution
115
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
116
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
117
+
118
+ ## Copyright
119
+
120
+ Copyright (c) 2011 Uchio Kondo <udzura@udzura.jp>. See LICENSE for
121
+ further details.
data/index.html ADDED
@@ -0,0 +1,108 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset='utf-8'>
5
+
6
+ <title>udzura/rack-block @ GitHub</title>
7
+
8
+ <style type="text/css">
9
+ body {
10
+ margin-top: 1.0em;
11
+ background-color: #d25b93;
12
+ font-family: Helvetica, Arial, FreeSans, san-serif;
13
+ color: #000000;
14
+ }
15
+ #container {
16
+ margin: 0 auto;
17
+ width: 700px;
18
+ }
19
+ h1 { font-size: 3.8em; color: #2da46c; margin-bottom: 3px; }
20
+ h1 .small { font-size: 0.4em; }
21
+ h1 a { text-decoration: none }
22
+ h2 { font-size: 1.5em; color: #2da46c; }
23
+ h3 { text-align: center; color: #2da46c; }
24
+ a { color: #2da46c; }
25
+ .description { font-size: 1.2em; margin-bottom: 30px; margin-top: 30px; font-style: italic;}
26
+ .download { float: right; }
27
+ pre { background: #000; color: #fff; padding: 15px;}
28
+ hr { border: 0; width: 80%; border-bottom: 1px solid #aaa}
29
+ .footer { text-align:center; padding-top:30px; font-style: italic; }
30
+ </style>
31
+ </head>
32
+
33
+ <body>
34
+ <a href="https://github.com/udzura/rack-block"><img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub" /></a>
35
+
36
+ <div id="container">
37
+
38
+ <div class="download">
39
+ <a href="https://github.com/udzura/rack-block/zipball/master">
40
+ <img border="0" width="90" src="https://github.com/images/modules/download/zip.png"></a>
41
+ <a href="https://github.com/udzura/rack-block/tarball/master">
42
+ <img border="0" width="90" src="https://github.com/images/modules/download/tar.png"></a>
43
+ </div>
44
+
45
+ <h1><a href="https://github.com/udzura/rack-block">rack-block</a>
46
+ <span class="small">by <a href="https://github.com/udzura">udzura</a></span></h1>
47
+
48
+ <div class="description">
49
+ A rack middleware for handling search bot access, ip block, etc.
50
+ </div>
51
+
52
+
53
+
54
+
55
+ <h2>Dependencies</h2>
56
+ <p>rack (>= 1.3)</p>
57
+
58
+
59
+
60
+ <h2>Install</h2>
61
+ <p> gem install rack-block
62
+
63
+ then edit `config.ru`:
64
+ use Rack::Block do
65
+ bot_access do
66
+ path '/foo' do
67
+ halt 404
68
+ end
69
+ end
70
+ end
71
+ run YourApp.new
72
+ </p>
73
+
74
+
75
+
76
+ <h2>License</h2>
77
+ <p>MIT License.</p>
78
+
79
+
80
+
81
+ <h2>Authors</h2>
82
+ <p>Uchio Kondo (udzura@udzura.jp)
83
+
84
+
85
+
86
+ <h2>Contact</h2>
87
+ <p>Uchio Kondo (udzura@udzura.jp)
88
+
89
+
90
+ <h2>Download</h2>
91
+ <p>
92
+ You can download this project in either
93
+ <a href="https://github.com/udzura/rack-block/zipball/master">zip</a> or
94
+ <a href="https://github.com/udzura/rack-block/tarball/master">tar formats.
95
+ </p>
96
+ <p>You can also clone the project with <a href="http://git-scm.com">Git</a>
97
+ by running:
98
+ <pre>$ git clone git://github.com/udzura/rack-block</pre>
99
+ </p>
100
+
101
+ <div class="footer">
102
+ get the source code on GitHub : <a href="https://github.com/udzura/rack-block">udzura/rack-block</a>
103
+ </div>
104
+
105
+ </div>
106
+
107
+ </body>
108
+ </html>
data/lib/rack/block.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rack'
2
2
  module Rack
3
3
  class Block
4
- autoload :DSL, 'rack/block/dsl'
4
+ require 'rack/block/dsl'
5
5
 
6
6
  include DSL::Matchers
7
7
  include DSL::Responses
@@ -26,11 +26,23 @@ module Rack
26
26
  path_matchers.each_pair do |path, action_with_args|
27
27
  if path =~ req.path_info
28
28
  action, *args = action_with_args
29
- return send action, *args
29
+ return send action, req, *args
30
30
  end
31
31
  end
32
32
  end
33
33
  end
34
+
35
+ self.ip_matchers.each_pair do |pattern, path_matchers|
36
+ if pattern =~ req.ip
37
+ path_matchers.each_pair do |path, action_with_args|
38
+ if path =~ req.path_info
39
+ action, *args = action_with_args
40
+ return send action, req, *args
41
+ end
42
+ end
43
+ end
44
+ end
45
+
34
46
  app.call(env)
35
47
  end
36
48
  # Your code goes here...
@@ -1,9 +1,8 @@
1
1
  module Rack
2
2
  class Block
3
3
  module DSL
4
- autoload :Matchers, 'rack/block/dsl/matchers'
5
- autoload :Responses, 'rack/block/dsl/responses'
6
4
  end
7
5
  end
8
6
  end
9
-
7
+ require 'rack/block/dsl/matchers'
8
+ require 'rack/block/dsl/responses'
File without changes
@@ -0,0 +1,21 @@
1
+ # patterns barrowed from CodeIgniter's helper
2
+ # thanks:
3
+ # https://github.com/EllisLab/CodeIgniter/blob/develop/application/config/user_agents.php#L200
4
+ # http://www.useragentstring.com/pages/useragentstring.php
5
+ # TODO more more bot sample
6
+ module Rack::Block::DSL
7
+ module Matchers
8
+ BUILTIN_BOT_PATTERN = /#{
9
+ ["Googlebot",
10
+ "MSNBot",
11
+ "Bing",
12
+ "Inktomi Slurp",
13
+ "Yahoo",
14
+ "AskJeeves",
15
+ "FastCrawler",
16
+ "InfoSeek Robot 1.0",
17
+ "Baiduspider",
18
+ "Lycos"].join("|")
19
+ }/i
20
+ end
21
+ end
@@ -1,11 +1,11 @@
1
+ require 'rack/block/dsl/builtin_bot_pattern'
1
2
  module Rack::Block::DSL
2
3
  module Matchers
3
- BUILTIN_BOT_PATTERN = /googlebot/i
4
-
5
4
  def bot_access(&block)
6
5
  ua_pattern BUILTIN_BOT_PATTERN, &block
7
6
  end
8
7
 
8
+ # TODO it's NO DRY
9
9
  def ua_pattern(pattern, &block)
10
10
  @_current_matching_type, orig = :by_UA, @_current_matching_type
11
11
  @_current_matching_ua_pattern, orig_ptn = pattern, @_current_matching_ua_pattern
@@ -15,11 +15,44 @@ module Rack::Block::DSL
15
15
  @_current_matching_type = orig
16
16
  end
17
17
 
18
+ def ip_pattern(pattern, &block)
19
+ @_current_matching_type, orig = :by_IP, @_current_matching_type
20
+ @_current_matching_ip_pattern, orig_ptn = ip_to_pattern(pattern), @_current_matching_ip_pattern
21
+ yield
22
+ ensure
23
+ @_current_matching_ip_pattern = orig_ptn
24
+ @_current_matching_type = orig
25
+ end
26
+
27
+ alias block_ua ua_pattern
28
+ alias block_ip ip_pattern
29
+
18
30
  def path(pattern, &block)
19
31
  @_current_matching_path, orig = pattern, @_current_matching_path
20
32
  yield
21
33
  ensure
22
34
  @_current_matching_path = orig
23
35
  end
36
+
37
+ private
38
+ def ip_to_pattern(ip_pattern)
39
+ case ip_pattern
40
+ when /^(\d+)(\.\d+){3}$/
41
+ Regexp.compile("^" + ip_pattern.gsub('.', '\\.') + "$")
42
+ when /^(\d+)(\.\d+){0,2}\.?$/
43
+ ip_pattern = ip_pattern.sub(/\.$/, '')
44
+ Regexp.compile("^" + ip_pattern.gsub('.', '\\.') + '(\\.\\d+)+' + "$")
45
+ else
46
+ raise ArgumentError, 'passed invalid IP string'
47
+ end
48
+ end
49
+
50
+ def in_ua_block?
51
+ @_current_matching_type == :by_UA
52
+ end
53
+
54
+ def in_ip_block?
55
+ @_current_matching_type == :by_IP
56
+ end
24
57
  end
25
58
  end
@@ -1,9 +1,18 @@
1
1
  module Rack::Block::DSL
2
2
  module Responses
3
+ def detect_matching_pattern
4
+ if in_ua_block?
5
+ ua_matchers[@_current_matching_ua_pattern] ||= {}
6
+ elsif in_ip_block?
7
+ ip_matchers[@_current_matching_ip_pattern] ||= {}
8
+ end
9
+ end
10
+
11
+ # TODO non DRY on handling `@_current_matching_path' !!!! it is terrible!!
3
12
  def halt(code, opts={})
4
13
  if @_current_matching_path
5
- path = Regexp.compile("^" + @_current_matching_path.sub(/\*/, '.*'))
6
- current_matchers = (self.ua_matchers[@_current_matching_ua_pattern] ||= {})
14
+ path = Regexp.compile("^" + @_current_matching_path.gsub(/\./, '\\.').gsub(/\*/, '.*'))
15
+ current_matchers = detect_matching_pattern
7
16
  current_matchers[path] = [:do_halt, code, opts]
8
17
  else
9
18
  path '*' do
@@ -12,10 +21,59 @@ module Rack::Block::DSL
12
21
  end
13
22
  end
14
23
 
15
- def do_halt(code, opts={})
24
+ def redirect(dest_path, opts={})
25
+ if @_current_matching_path
26
+ path = Regexp.compile("^" + @_current_matching_path.gsub(/\./, '\\.').gsub(/\*/, '.*'))
27
+ current_matchers = detect_matching_pattern
28
+ current_matchers[path] = [:do_redirect, dest_path, opts]
29
+ else
30
+ path '*' do
31
+ redirect dest_path, opts
32
+ end
33
+ end
34
+ end
35
+
36
+ def dummy_app(opts={}, &app_proc)
37
+ if @_current_matching_path
38
+ path = Regexp.compile("^" + @_current_matching_path.gsub(/\./, '\\.').gsub(/\*/, '.*'))
39
+ current_matchers = detect_matching_pattern
40
+ current_matchers[path] = [:do_dummy_app, app_proc, opts]
41
+ else
42
+ path '*' do
43
+ dummy_app opts, &app_proc
44
+ end
45
+ end
46
+ end
47
+
48
+ alias_method :double, :dummy_app
49
+
50
+ private
51
+ def do_halt(req, code, opts={})
16
52
  headers = {"Content-Type" => "text/plain"}.merge(opts[:headers] || {})
17
53
  body = opts[:body] || "Halt!"
18
54
  return [code, headers, [body]]
19
55
  end
56
+
57
+ def do_redirect(req, dest_path, opts={})
58
+ dest_full_path = case dest_path
59
+ when /^https?:\/\//
60
+ dest_path
61
+ else
62
+ uri = URI.parse req.url
63
+ uri.path = dest_path
64
+ uri.to_s
65
+ end
66
+ code = opts[:status_code] || 301
67
+ return [code, {"Location" => dest_full_path}, []]
68
+ end
69
+
70
+ def do_dummy_app(req, app_proc, opts={})
71
+ case app_proc.arity
72
+ when 0
73
+ return app_proc.call.call(req.env)
74
+ else
75
+ return app_proc.call(req.env)
76
+ end
77
+ end
20
78
  end
21
79
  end
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  class Block
3
- VERSION = "0.0.1.pre1"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
data/rack-block.gemspec CHANGED
@@ -7,9 +7,9 @@ Gem::Specification.new do |s|
7
7
  s.version = Rack::Block::VERSION
8
8
  s.authors = ["Uchio Kondo"]
9
9
  s.email = ["udzura@udzura.jp"]
10
- s.homepage = ""
11
- s.summary = %q{A rack middleware for handling search bot access, ip block, etc.}
12
- s.description = %q{A rack middleware for handling search bot access, ip block, etc.}
10
+ s.homepage = "http://udzura.jp/rack-block"
11
+ s.summary = %q{A rack middleware for controlling accesses by search bot or not, remote ip address, etc.}
12
+ s.description = %q{A rack middleware for controlling accesses by search bot or not, remote ip address, etc.}
13
13
 
14
14
  s.rubyforge_project = "rack-block"
15
15
 
@@ -20,7 +20,9 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_runtime_dependency "rack", '>= 1.3'
22
22
 
23
+ s.add_development_dependency "rake", '> 0'
23
24
  s.add_development_dependency "rspec", '>= 2'
24
25
  s.add_development_dependency "rack-test", '> 0'
26
+ s.add_development_dependency "sinatra", '> 1.0'
25
27
  s.add_development_dependency "guard-rspec"
26
28
  end
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/mock_app_helper')
3
+
4
+ describe "Blocking search bots" do
5
+ def access_root_as(ua)
6
+ header "User-Agent", ua
7
+ get '/'
8
+ end
9
+
10
+ before do
11
+ mock_app do
12
+ use Rack::Block do
13
+ bot_access { halt 404 }
14
+ end
15
+ run DEFAULT_APP
16
+ end
17
+ end
18
+
19
+ it 'blocks google bot' do
20
+ access_root_as 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'
21
+ last_response.should be_not_found
22
+ end
23
+
24
+ it 'blocks msn bot' do
25
+ access_root_as 'msnbot/1.1 (+http://search.msn.com/msnbot.htm)'
26
+ last_response.should be_not_found
27
+ end
28
+
29
+ it 'blocks bing bot' do
30
+ access_root_as 'Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)'
31
+ last_response.should be_not_found
32
+ end
33
+
34
+ it 'blocks yahoo! slurp' do
35
+ access_root_as 'Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)'
36
+ last_response.should be_not_found
37
+ end
38
+
39
+ it 'blocks baiduspider' do
40
+ access_root_as 'Baiduspider+(+http://www.baidu.com/search/spider_jp.html)'
41
+ last_response.should be_not_found
42
+ end
43
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/mock_app_helper')
3
+
4
+ describe "Blocking by IP" do
5
+ it 'blocks accesses from a specific IP' do
6
+ mock_app {
7
+ use Rack::Block do
8
+ ip_pattern '10.20.30.40' do
9
+ halt 404
10
+ end
11
+ end
12
+ run DEFAULT_APP
13
+ }
14
+
15
+ header "X-Forwarded-For", "10.20.30.40"
16
+ ['/', '/any', '/path/blocked'].each do |path|
17
+ get path
18
+ last_response.should be_not_found
19
+ end
20
+ end
21
+
22
+ it 'blocks accesses from a specific IP pattern' do
23
+ mock_app {
24
+ use Rack::Block do
25
+ ip_pattern '10.20.30.' do
26
+ halt 404
27
+ end
28
+ end
29
+ run DEFAULT_APP
30
+ }
31
+
32
+ header "X-Forwarded-For", "10.20.30.40"
33
+ ['/', '/any', '/path/blocked'].each do |path|
34
+ get path
35
+ last_response.should be_not_found
36
+ end
37
+
38
+ header "X-Forwarded-For", "10.20.30.50"
39
+ ['/', '/any', '/path/blocked'].each do |path|
40
+ get path
41
+ last_response.should be_not_found
42
+ end
43
+ end
44
+
45
+ it 'blocks accesses from a specific IP pattern(with a netmask)' do
46
+ pending "Not yet implemented, netmask expressions to Regexp or some other matching methods..."
47
+ mock_app {
48
+ use Rack::Block do
49
+ ip_pattern '10.20.30.0/24' do
50
+ halt 404
51
+ end
52
+ end
53
+ run DEFAULT_APP
54
+ }
55
+
56
+ header "X-Forwarded-For", "10.20.30.40"
57
+ ['/', '/any', '/path/blocked'].each do |path|
58
+ get path
59
+ last_response.should be_not_found
60
+ end
61
+
62
+ header "X-Forwarded-For", "10.20.30.50"
63
+ ['/', '/any', '/path/blocked'].each do |path|
64
+ get path
65
+ last_response.should be_not_found
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/mock_app_helper')
3
+
4
+ describe "Path matching patterns" do
5
+ it 'matching path should specified with `/\' starting' do
6
+ mock_app {
7
+ use Rack::Block do
8
+ bot_access { path('/foo'){ halt 404 } }
9
+ end
10
+ run DEFAULT_APP
11
+ }
12
+
13
+ header "User-Agent", "Googlebot"
14
+ get '/foo'
15
+ last_response.should be_not_found
16
+
17
+ get '/bar/foo'
18
+ last_response.should be_ok
19
+ end
20
+
21
+ it 'matching glob `*\' should be a wildcard' do
22
+ mock_app {
23
+ use Rack::Block do
24
+ bot_access { path('/foo/*/bar'){ halt 500 } }
25
+ end
26
+ run DEFAULT_APP
27
+ }
28
+
29
+ header "User-Agent", "Googlebot"
30
+ get '/foo/123/bar'
31
+ last_response.should be_server_error
32
+
33
+ get '/foo/hogehoge/bar/4'
34
+ last_response.should be_server_error
35
+ end
36
+
37
+ it 'path including `.\' should be sane' do
38
+ mock_app {
39
+ use Rack::Block do
40
+ bot_access { path('/favicon.ico'){ halt 404 } }
41
+ end
42
+ run DEFAULT_APP
43
+ }
44
+
45
+ header "User-Agent", "Googlebot"
46
+ get '/favicon.ico'
47
+ last_response.should be_not_found
48
+
49
+ header "User-Agent", "Googlebot"
50
+ get '/favicon_ico'
51
+ last_response.should be_ok
52
+ end
53
+ end
@@ -0,0 +1,133 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/mock_app_helper')
3
+
4
+ describe "Response value verbs" do
5
+ before do
6
+ end
7
+
8
+ it 'can halt with status code 404' do
9
+ mock_app {
10
+ use Rack::Block do
11
+ bot_access { path('*'){ halt 404 } }
12
+ end
13
+ run DEFAULT_APP
14
+ }
15
+
16
+ header "User-Agent", "Googlebot"
17
+ get '/'
18
+ last_response.should be_not_found
19
+ end
20
+
21
+ it 'can halt with status code 500' do
22
+ mock_app {
23
+ use Rack::Block do
24
+ bot_access { path('*'){ halt 500 } }
25
+ end
26
+ run DEFAULT_APP
27
+ }
28
+
29
+ header "User-Agent", "Googlebot"
30
+ get '/'
31
+ last_response.status.should eq(500)
32
+ end
33
+
34
+ it 'can redirect' do
35
+ mock_app {
36
+ use Rack::Block do
37
+ bot_access { path('*'){ redirect 'http://www.google.com/' } }
38
+ end
39
+ run DEFAULT_APP
40
+ }
41
+
42
+ header "User-Agent", "Googlebot"
43
+ get '/'
44
+ last_response.should be_redirect
45
+ end
46
+
47
+ it 'can redirect internal' do
48
+ mock_app {
49
+ use Rack::Block do
50
+ bot_access { path('/foo/*'){ redirect '/' } }
51
+ end
52
+ run DEFAULT_APP
53
+ }
54
+
55
+ header "User-Agent", "Googlebot"
56
+ get '/foo/bar'
57
+ last_response.should be_redirect
58
+
59
+ follow_redirect!
60
+ last_response.body.should match /It is summer/
61
+ end
62
+
63
+ context 'doubling application' do
64
+ require 'sinatra/base'
65
+ let :dummy do
66
+ Class.new(Sinatra::Base) do
67
+ get '/' do
68
+ "This is a dummy access to: #{request.path_info}"
69
+ end
70
+ end
71
+ end
72
+
73
+ it 'can point access to a dummy application' do
74
+ dummy = dummy()
75
+ mock_app {
76
+ use Rack::Block do
77
+ bot_access do
78
+ path('*') do
79
+ dummy_app { dummy.new }
80
+ end
81
+ end
82
+ end
83
+ run DEFAULT_APP
84
+ }
85
+
86
+ header "User-Agent", "Googlebot"
87
+ get '/'
88
+ last_response.body.should match /This is a dummy access to: \//
89
+
90
+ get '/not-found'
91
+ last_response.should be_not_found
92
+ end
93
+
94
+ it 'should be called with env' do
95
+ dummy = dummy()
96
+ mock_app {
97
+ use Rack::Block do
98
+ bot_access do
99
+ path('*') do
100
+ double do |env|
101
+ # Sinatra::Base and its subclasses have a #call method in his class methods
102
+ dummy.call(env)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ run DEFAULT_APP
108
+ }
109
+
110
+ header "User-Agent", "Googlebot"
111
+ get '/'
112
+ last_response.body.should match /This is a dummy access to: \//
113
+ end
114
+
115
+ it 'should be aliased by #double' do
116
+ dummy = dummy()
117
+ mock_app {
118
+ use Rack::Block do
119
+ bot_access do
120
+ path('*') do
121
+ double { dummy.new }
122
+ end
123
+ end
124
+ end
125
+ run DEFAULT_APP
126
+ }
127
+
128
+ header "User-Agent", "Googlebot"
129
+ get '/'
130
+ last_response.body.should match /This is a dummy access to: \//
131
+ end
132
+ end
133
+ end
@@ -2,23 +2,6 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
  require File.expand_path(File.dirname(__FILE__) + '/mock_app_helper')
3
3
 
4
4
  describe "Blocking by UA" do
5
- before do
6
- mock_app {
7
- use Rack::Block do
8
- bot_access do
9
- path '/foo' do
10
- halt 404
11
- end
12
-
13
- path '/bar' do
14
- redirect '/'
15
- end
16
- end
17
- end
18
- run DEFAULT_APP
19
- }
20
- end
21
-
22
5
  describe "Blocking built-in bot UA pattern" do
23
6
 
24
7
  it "blocks all bot access if no nesting block" do
@@ -50,14 +33,55 @@ describe "Blocking by UA" do
50
33
  run DEFAULT_APP
51
34
  }
52
35
 
36
+ header "User-Agent", "Googlebot"
37
+ get '/foo'
38
+ last_response.should be_not_found
39
+ end
40
+
41
+ it "does not block excepting specified paths" do
42
+ mock_app {
43
+ use Rack::Block do
44
+ bot_access do
45
+ path '/foo' do
46
+ halt 404
47
+ end
48
+ end
49
+ end
50
+ run DEFAULT_APP
51
+ }
52
+
53
53
  header "User-Agent", "Googlebot"
54
54
  get '/'
55
55
  last_response.should be_ok
56
+ end
57
+ end
56
58
 
57
- get '/foo'
58
- last_response.should be_not_found
59
+ describe "Blocking customized UA pattern" do
60
+ before do
61
+ mock_app {
62
+ use Rack::Block do
63
+ ua_pattern /MSIE [678]\.[05].*Windows/ do
64
+ halt 404
65
+ end
66
+ end
67
+ run DEFAULT_APP
68
+ }
59
69
  end
60
70
 
61
- it "does not block excepting specified paths"
71
+ it "blocks customized UA" do
72
+ header "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
73
+ ['/', '/any', '/path/blocked'].each do |path|
74
+ get path
75
+ last_response.should be_not_found
76
+ end
77
+ end
78
+
79
+ it "doesn't block non-matching UA" do
80
+ header "User-Agent", "Mozilla/5.0 (Ubuntu; X11; Linux i686; rv:8.0) Gecko/20100101 Firefox/8.0"
81
+ ['/', '/any', '/path/not-blocked'].each do |path|
82
+ get path
83
+ last_response.should be_ok
84
+ end
85
+ end
62
86
  end
63
87
  end
metadata CHANGED
@@ -1,19 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-block
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.pre1
5
- prerelease: 6
4
+ version: 0.1.0
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Uchio Kondo
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-10 00:00:00.000000000Z
12
+ date: 2011-12-24 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
16
- requirement: &76848810 !ruby/object:Gem::Requirement
16
+ requirement: &85009500 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,21 @@ dependencies:
21
21
  version: '1.3'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *76848810
24
+ version_requirements: *85009500
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &85009210 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>'
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *85009210
25
36
  - !ruby/object:Gem::Dependency
26
37
  name: rspec
27
- requirement: &76848430 !ruby/object:Gem::Requirement
38
+ requirement: &85008940 !ruby/object:Gem::Requirement
28
39
  none: false
29
40
  requirements:
30
41
  - - ! '>='
@@ -32,10 +43,10 @@ dependencies:
32
43
  version: '2'
33
44
  type: :development
34
45
  prerelease: false
35
- version_requirements: *76848430
46
+ version_requirements: *85008940
36
47
  - !ruby/object:Gem::Dependency
37
48
  name: rack-test
38
- requirement: &76847930 !ruby/object:Gem::Requirement
49
+ requirement: &85008680 !ruby/object:Gem::Requirement
39
50
  none: false
40
51
  requirements:
41
52
  - - ! '>'
@@ -43,10 +54,21 @@ dependencies:
43
54
  version: '0'
44
55
  type: :development
45
56
  prerelease: false
46
- version_requirements: *76847930
57
+ version_requirements: *85008680
58
+ - !ruby/object:Gem::Dependency
59
+ name: sinatra
60
+ requirement: &85008300 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>'
64
+ - !ruby/object:Gem::Version
65
+ version: '1.0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *85008300
47
69
  - !ruby/object:Gem::Dependency
48
70
  name: guard-rspec
49
- requirement: &76847490 !ruby/object:Gem::Requirement
71
+ requirement: &85008070 !ruby/object:Gem::Requirement
50
72
  none: false
51
73
  requirements:
52
74
  - - ! '>='
@@ -54,8 +76,9 @@ dependencies:
54
76
  version: '0'
55
77
  type: :development
56
78
  prerelease: false
57
- version_requirements: *76847490
58
- description: A rack middleware for handling search bot access, ip block, etc.
79
+ version_requirements: *85008070
80
+ description: A rack middleware for controlling accesses by search bot or not, remote
81
+ ip address, etc.
59
82
  email:
60
83
  - udzura@udzura.jp
61
84
  executables: []
@@ -64,22 +87,32 @@ extra_rdoc_files: []
64
87
  files:
65
88
  - .gitignore
66
89
  - .rspec
90
+ - .travis.yml
67
91
  - Gemfile
68
92
  - Gemfile.lock
69
93
  - Guardfile
94
+ - LICENSE
95
+ - README.md
70
96
  - Rakefile
97
+ - index.html
71
98
  - lib/rack-block.rb
72
99
  - lib/rack/block.rb
73
100
  - lib/rack/block/dsl.rb
101
+ - lib/rack/block/dsl/bot_ua_pattern.rb
102
+ - lib/rack/block/dsl/builtin_bot_pattern.rb
74
103
  - lib/rack/block/dsl/matchers.rb
75
104
  - lib/rack/block/dsl/responses.rb
76
105
  - lib/rack/block/version.rb
77
106
  - rack-block.gemspec
107
+ - spec/integrations/bot_pattern_spec.rb
108
+ - spec/integrations/ip_blocking_spec.rb
78
109
  - spec/integrations/mock_app_helper.rb
79
110
  - spec/integrations/mock_app_works_spec.rb
111
+ - spec/integrations/path_matching_spec.rb
112
+ - spec/integrations/response_verbs_spec.rb
80
113
  - spec/integrations/ua_blocking_spec.rb
81
114
  - spec/spec_helper.rb
82
- homepage: ''
115
+ homepage: http://udzura.jp/rack-block
83
116
  licenses: []
84
117
  post_install_message:
85
118
  rdoc_options: []
@@ -94,13 +127,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
94
127
  required_rubygems_version: !ruby/object:Gem::Requirement
95
128
  none: false
96
129
  requirements:
97
- - - ! '>'
130
+ - - ! '>='
98
131
  - !ruby/object:Gem::Version
99
- version: 1.3.1
132
+ version: '0'
100
133
  requirements: []
101
134
  rubyforge_project: rack-block
102
135
  rubygems_version: 1.8.10
103
136
  signing_key:
104
137
  specification_version: 3
105
- summary: A rack middleware for handling search bot access, ip block, etc.
138
+ summary: A rack middleware for controlling accesses by search bot or not, remote ip
139
+ address, etc.
106
140
  test_files: []