rack-ip_filter 0.0.2 → 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/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Rack::IpFilter
2
2
 
3
- TODO: Write a gem description
3
+ A Rack middleware component which does simple White and Black list filtering of remote IP Adresses.
4
+
5
+ Provides support for CIDR notation for ranges as well as specific addresses.
4
6
 
5
7
  ## Installation
6
8
 
@@ -18,7 +20,29 @@ Or install it yourself as:
18
20
 
19
21
  ## Usage
20
22
 
21
- TODO: Write usage instructions here
23
+ First require:
24
+
25
+ require 'rack/ip_filter'
26
+
27
+ For Rails, you can insert the middleware in your `config/application.rb`:
28
+
29
+ IP_WHITELIST = %w(192.168.2.0/24 127.0.0.1)
30
+
31
+ module YourApp
32
+ class Application < Rails::Application
33
+ config.middleware.use Rack::IpFilter, IpFilter::WhiteList.new(::IP_WHITELIST)
34
+ end
35
+ end
36
+
37
+ See example/app.rb for a simple Sinatra app which illustrates proper usage.
38
+
39
+ ## Options
40
+
41
+ Rack::IpFilter takes two arguments, the first is an object that responds to `approved?` and returns a boolean.
42
+ The second argument is the path to apply the filter, defaults to root: `'/'`.
43
+
44
+ IpFilter::WhiteList and IpFilter::Black list ship with the gem and explicitly allow or block remote ip addresses
45
+ respectively.
22
46
 
23
47
  ## Contributing
24
48
 
@@ -0,0 +1,22 @@
1
+ require 'sinatra/base'
2
+
3
+ $LOAD_PATH << File.dirname(__FILE__) + '/../lib'
4
+
5
+ require 'rack/ip_filter'
6
+
7
+ # rackup -s thin app.rb
8
+ # http://localhost:9292/test
9
+ class App < Sinatra::Base
10
+
11
+ use Rack::IpFilter, IpFilter::WhiteList.new('192.168.2.0/24', '127.0.0.1'), '/'
12
+ use Rack::IpFilter, IpFilter::WhiteList.new('127.0.0.1'), '/admin'
13
+ use Rack::IpFilter, IpFilter::BlackList.new('192.168.2.23'), '/'
14
+
15
+ set :root, File.dirname(__FILE__)
16
+
17
+ get '/test' do
18
+ content_type "text/plain"
19
+ body "Hello world!"
20
+ end
21
+
22
+ end
@@ -1 +1,11 @@
1
+ require 'ipaddr'
2
+ require 'ip_filter/list'
3
+ require 'ip_filter/white_list'
4
+ require 'ip_filter/black_list'
1
5
  require 'rack/ip_filter'
6
+
7
+ module IpFilter
8
+
9
+ VERSION = '0.1.0'
10
+
11
+ end
@@ -0,0 +1,9 @@
1
+ module IpFilter
2
+
3
+ class BlackList < List
4
+
5
+ def approved?(remote_ip)
6
+ !any?(remote_ip)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module IpFilter
2
+
3
+ class List
4
+ def initialize(*list)
5
+ @list = list.flatten.map { |ip| IPAddr.new(ip) }
6
+ end
7
+
8
+ def any?(remote_ip)
9
+ @list.any? { |ip| ip.include?(remote_ip) }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module IpFilter
2
+
3
+ class WhiteList < List
4
+
5
+ def approved?(remote_ip)
6
+ any?(remote_ip)
7
+ end
8
+ end
9
+ end
@@ -1,36 +1,28 @@
1
- require 'netaddr'
1
+ require 'ip_filter'
2
2
 
3
3
  module Rack
4
4
 
5
5
  class IpFilter
6
6
 
7
- VERSION = "0.0.2"
8
-
9
- def initialize(app, ip_whitelist, path)
10
- @app = app
11
- @ip_whitelist = ip_whitelist.map { |ip| NetAddr::CIDR.create(ip) }
7
+ def initialize(app, list, path = '/')
8
+ @app = app
12
9
  @path = path
10
+ @list = list
13
11
  end
14
12
 
15
13
  def call(env)
16
- if white_listed?(env)
14
+ if approved?(env)
17
15
  @app.call(env)
18
16
  else
19
17
  forbidden!
20
18
  end
21
19
  end
22
-
23
- def white_listed?(env)
24
- return true unless env['REQUEST_PATH'] =~ /^#{@path}/
25
-
26
- remote_addr = remote_address(env)
27
- remote_addr == '127.0.0.1' || @ip_whitelist.any? { |ip_range| ip_range.contains?(remote_addr) }
28
- end
29
20
 
30
- def black_listed?(env)
31
-
21
+ def approved?(env)
22
+ return true unless path_match?(env['REQUEST_PATH'])
23
+ @list.approved?(remote_address(env))
32
24
  end
33
-
25
+
34
26
  def remote_address(env)
35
27
  if env['HTTP_X_FORWARDED_FOR']
36
28
  env['HTTP_X_FORWARDED_FOR'].split(',').first.strip
@@ -43,5 +35,9 @@ module Rack
43
35
  [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, []]
44
36
  end
45
37
 
38
+ def path_match?(path)
39
+ path =~ /^#{@path}/
40
+ end
41
+
46
42
  end
47
43
  end
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  lib = File.expand_path('../lib/', __FILE__)
3
3
  $:.unshift lib unless $:.include?(lib)
4
- require 'rack/ip_filter'
4
+ require 'ip_filter'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
7
  gem.authors = ["Mike Evans"]
@@ -18,5 +18,5 @@ Gem::Specification.new do |gem|
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
19
  gem.name = "rack-ip_filter"
20
20
  gem.require_paths = ["lib"]
21
- gem.version = Rack::IpFilter::VERSION
21
+ gem.version = IpFilter::VERSION
22
22
  end
@@ -1,4 +1,5 @@
1
1
  require 'minitest/autorun'
2
+ require 'ip_filter'
2
3
  require 'rack'
3
4
  require 'rack/test'
4
5
  require 'rack/ip_filter'
@@ -0,0 +1,26 @@
1
+ require 'helper'
2
+
3
+ class TestWhiteList < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @range = '192.168.2.0/24'
7
+ @included = '192.168.2.100'
8
+ @not_included = '192.168.3.0'
9
+ end
10
+
11
+ def test_ip_approved
12
+ list = IpFilter::WhiteList.new(@range)
13
+ assert !list.approved?(@included)
14
+ end
15
+
16
+ def test_ip_restricted
17
+ list = IpFilter::WhiteList.new(@range)
18
+ assert list.approved?(@not_included)
19
+ end
20
+
21
+ def test_allows_arrays
22
+ list = IpFilter::WhiteList.new([@range, @not_included])
23
+ assert !list.approved?(@included)
24
+ end
25
+
26
+ end
@@ -1,43 +1,47 @@
1
1
  require 'helper'
2
2
 
3
- class IpWhitelistTest < MiniTest::Unit::TestCase
3
+ class TestRackIpFilter < MiniTest::Unit::TestCase
4
4
  include Rack::Test::Methods
5
5
 
6
- LOCAL_IP = '127.0.0.1'
7
- GOOD_IP = '24.40.64.23'
8
- BAD_IP = '9.9.9.9'
6
+ def setup
7
+ @range = '24.40.64.0/20'
8
+ @local = '127.0.0.1'
9
+ @good = '24.40.64.23'
10
+ @bad = '9.9.9.9'
11
+ @list = [@range, @local]
12
+ end
9
13
 
10
14
  def app
11
- Rack::IpFilter.new(lambda {|env| [200, {}, []] }, ['24.40.64.0/20'], '/')
15
+ Rack::IpFilter.new(lambda {|env| [200, {}, []] }, IpFilter::WhiteList.new(@list), '/')
12
16
  end
13
17
 
14
18
  def test_local_ip_address_admitted
15
- get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => LOCAL_IP }
19
+ get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => @local }
16
20
  assert last_response.ok?
17
21
  end
18
22
 
19
23
  def test_allowed_remote_ip_address_admitted
20
- get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => GOOD_IP }
24
+ get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => @good }
21
25
  assert last_response.ok?
22
26
  end
23
27
 
24
28
  def test_outside_remote_ip_address_rejected
25
- get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => BAD_IP }
29
+ get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => @bad }
26
30
  assert !last_response.ok?
27
31
  end
28
32
 
29
33
  def test_local_ip_address_admitted_via_proxy
30
- get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [LOCAL_IP, BAD_IP].join(', ') }
34
+ get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [@local, @bad].join(', ') }
31
35
  assert last_response.ok?
32
36
  end
33
37
 
34
38
  def test_allowed_remote_ip_address_admitted_via_proxy
35
- get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [GOOD_IP, BAD_IP].join(', ') }
39
+ get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [@good, @bad].join(', ') }
36
40
  assert last_response.ok?
37
41
  end
38
42
 
39
43
  def test_outside_remote_ip_address_rejected_via_proxy
40
- get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [BAD_IP, GOOD_IP].join(', ') }
44
+ get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [@bad, @good].join(', ') }
41
45
  assert !last_response.ok?
42
46
  end
43
47
 
@@ -0,0 +1,26 @@
1
+ require 'helper'
2
+
3
+ class TestWhiteList < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @range = '192.168.2.0/24'
7
+ @included = '192.168.2.100'
8
+ @not_included = '192.168.3.0'
9
+ end
10
+
11
+ def test_ip_approved
12
+ list = IpFilter::WhiteList.new(@range)
13
+ assert list.approved?(@included)
14
+ end
15
+
16
+ def test_ip_restricted
17
+ list = IpFilter::WhiteList.new(@range)
18
+ assert !list.approved?(@not_included)
19
+ end
20
+
21
+ def test_allows_arrays
22
+ list = IpFilter::WhiteList.new([@range, @not_included])
23
+ assert list.approved?(@included)
24
+ end
25
+
26
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-ip_filter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-10 00:00:00.000000000 Z
12
+ date: 2012-05-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: netaddr
16
- requirement: &70234347589200 !ruby/object:Gem::Requirement
16
+ requirement: &70211260750580 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70234347589200
24
+ version_requirements: *70211260750580
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rack
27
- requirement: &70234347588740 !ruby/object:Gem::Requirement
27
+ requirement: &70211260744980 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70234347588740
35
+ version_requirements: *70211260744980
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rack-test
38
- requirement: &70234347588320 !ruby/object:Gem::Requirement
38
+ requirement: &70211260760140 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70234347588320
46
+ version_requirements: *70211260760140
47
47
  description: White and clacklist IPs
48
48
  email:
49
49
  - mike@urlgonomics.com
@@ -56,11 +56,17 @@ files:
56
56
  - LICENSE
57
57
  - README.md
58
58
  - Rakefile
59
+ - example/app.rb
59
60
  - lib/ip_filter.rb
61
+ - lib/ip_filter/black_list.rb
62
+ - lib/ip_filter/list.rb
63
+ - lib/ip_filter/white_list.rb
60
64
  - lib/rack/ip_filter.rb
61
65
  - rack-ip_filter.gemspec
62
66
  - test/helper.rb
63
- - test/test_ip_filter.rb
67
+ - test/test_black_list.rb
68
+ - test/test_rack_ip_filter.rb
69
+ - test/test_white_list.rb
64
70
  homepage: ''
65
71
  licenses: []
66
72
  post_install_message:
@@ -87,4 +93,6 @@ specification_version: 3
87
93
  summary: ''
88
94
  test_files:
89
95
  - test/helper.rb
90
- - test/test_ip_filter.rb
96
+ - test/test_black_list.rb
97
+ - test/test_rack_ip_filter.rb
98
+ - test/test_white_list.rb