ip_filter 0.8.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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +1 -0
  4. data/CHANGELOG +29 -0
  5. data/Gemfile.lock +117 -0
  6. data/LICENSE +20 -0
  7. data/README.rdoc +232 -0
  8. data/Rakefile +6 -0
  9. data/data/geoip/country_code.yml +255 -0
  10. data/data/geoip/country_code3.yml +255 -0
  11. data/data/geoip/country_continent.yml +255 -0
  12. data/data/geoip/country_name.yml +255 -0
  13. data/data/geoip/time_zone.yml +677 -0
  14. data/lib/geoip.rb +559 -0
  15. data/lib/ip_filter.rb +100 -0
  16. data/lib/ip_filter/cache.rb +30 -0
  17. data/lib/ip_filter/cache/dallistore.rb +39 -0
  18. data/lib/ip_filter/cache/redis.rb +26 -0
  19. data/lib/ip_filter/configuration.rb +47 -0
  20. data/lib/ip_filter/controller/geo_ip_lookup.rb +78 -0
  21. data/lib/ip_filter/lookups/base.rb +60 -0
  22. data/lib/ip_filter/lookups/geoip.rb +41 -0
  23. data/lib/ip_filter/providers/max_mind.rb +52 -0
  24. data/lib/ip_filter/providers/s3.rb +51 -0
  25. data/lib/ip_filter/railtie.rb +23 -0
  26. data/lib/ip_filter/request.rb +14 -0
  27. data/lib/ip_filter/results/base.rb +39 -0
  28. data/lib/ip_filter/results/geoip.rb +19 -0
  29. data/lib/ip_filter/version.rb +3 -0
  30. data/spec/cache/dallistore_spec.rb +16 -0
  31. data/spec/cache/redis_spec.rb +56 -0
  32. data/spec/controller/ip_controller_spec.rb +56 -0
  33. data/spec/fixtures/GeoIP.dat +0 -0
  34. data/spec/fixtures/LICENSE.txt +31 -0
  35. data/spec/fixtures/country.dat +0 -0
  36. data/spec/ip_filter_spec.rb +19 -0
  37. data/spec/providers/max_mind_spec.rb +11 -0
  38. data/spec/providers/s3_spec.rb +11 -0
  39. data/spec/spec_helper.rb +40 -0
  40. data/spec/support/enable_dallistore_cache.rb +15 -0
  41. data/spec/support/enable_redis_cache.rb +15 -0
  42. metadata +85 -0
@@ -0,0 +1,51 @@
1
+ require 'aws-sdk'
2
+ require 'aws-sdk-v1'
3
+
4
+ module IpFilter
5
+ module Providers
6
+ class S3
7
+ attr_accessor :remote, :bucket_name, :urls
8
+
9
+ def initialize
10
+ @bucket_name = IpFilter.configuration.s3_bucket_name
11
+ AWS.config(
12
+ access_key_id: IpFilter.configuration.s3_access_key_id,
13
+ secret_access_key: IpFilter.configuration.s3_secret_access_key
14
+ )
15
+ @remote = AWS::S3.new
16
+ @bucket = create_bucket
17
+ @urls = {}
18
+ return self
19
+ end
20
+
21
+ def create_bucket
22
+ bucket = remote.buckets[bucket_name]
23
+ unless bucket.exists?
24
+ bucket = remote.buckets.create(bucket_name)
25
+ end
26
+ return bucket
27
+ end
28
+
29
+ def upload!
30
+ IpFilter.database_files.each do |file|
31
+ file_name = File.basename(file)
32
+ obj = @bucket.objects[file_name].write(file: file)
33
+ urls[file_name] = obj.url_for(:read, expires: Time.now.to_i + 840_000)
34
+ end
35
+ urls
36
+ end
37
+
38
+ def download!(name = nil)
39
+ if name.nil?
40
+ name = File.basename(IpFilter.configuration.geo_ip_dat)
41
+ end
42
+ geoip_db = @bucket.objects[name]
43
+ File.open(IpFilter.configuration.geo_ip_dat, 'wb') do |file|
44
+ geoip_db.read do |chunk|
45
+ file.write(chunk)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,23 @@
1
+ require 'ip_filter'
2
+ require 'ip_filter/controller/geo_ip_lookup'
3
+
4
+ module IpFilter
5
+ if defined? Rails::Railtie
6
+ require 'rails'
7
+ class Railtie < Rails::Railtie
8
+ initializer 'ip_filter.insert_into_action_controller' do
9
+ ActiveSupport.on_load :action_controller do
10
+ IpFilter::Railtie.insert
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ class Railtie
17
+ def self.insert
18
+ if defined?(::ActionController::Base)
19
+ ::ActionController::Base.send :include, Controller::GeoIpLookup
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ require 'ip_filter'
2
+
3
+ module IpFilter
4
+ module Request
5
+ def location
6
+ # For now just grab the first value as the best guess.
7
+ @location ||= IpFilter.search(ip).try(:first)
8
+ end
9
+ end
10
+ end
11
+
12
+ if defined?(Rack) && defined?(Rack::Request)
13
+ Rack::Request.send :include, IpFilter::Request
14
+ end
@@ -0,0 +1,39 @@
1
+ module IpFilter
2
+ module Result
3
+ class Base
4
+ attr_accessor :data
5
+
6
+ def initialize(data)
7
+ @data = data
8
+ end
9
+
10
+ def [](attribute)
11
+ @data[attribute.to_sym]
12
+ end
13
+
14
+ def to_hash
15
+ @data
16
+ end
17
+
18
+ def country_code
19
+ raise NotImplementedError.new
20
+ end
21
+
22
+ def country_code2
23
+ raise NotImplementedError.new
24
+ end
25
+
26
+ def country_code3
27
+ raise NotImplementedError.new
28
+ end
29
+
30
+ def country_name
31
+ raise NotImplementedError.new
32
+ end
33
+
34
+ def continent_code
35
+ raise NotImplementedError.new
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,19 @@
1
+ require 'ip_filter/results/base'
2
+
3
+ module IpFilter
4
+ module Result
5
+ class Geoip < Base
6
+ def self.response_attributes
7
+ %w(
8
+ ip country_code country_code2 country_code3 country_name continent_code
9
+ )
10
+ end
11
+
12
+ response_attributes.each do |a|
13
+ define_method a do
14
+ @data[a.to_sym]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module IpFilter
2
+ VERSION = '0.8.0'
3
+ end
@@ -0,0 +1,16 @@
1
+ require 'active_support/cache'
2
+ require 'ip_filter'
3
+ require 'ip_filter/cache'
4
+ require 'ip_filter/cache/dallistore'
5
+ require 'spec_helper'
6
+
7
+ describe IpFilter::Cache::DalliStore do
8
+ extend EnableDallistoreCache
9
+ activate_dallistore!
10
+
11
+ subject { described_class.new(IpFilter.Configuration.cache) }
12
+
13
+ it { expect respond_to(:reset).with(0).arguments }
14
+ it { expect respond_to(:[]).with(1).arguments }
15
+ it { expect respond_to(:[]=).with(2).arguments }
16
+ end
@@ -0,0 +1,56 @@
1
+ require 'ip_filter'
2
+ require 'ip_filter/cache'
3
+ require 'ip_filter/cache/redis'
4
+ require 'spec_helper'
5
+
6
+ describe IpFilter::Cache::Redis do
7
+ extend EnableRedisCache
8
+ activate_redis!
9
+
10
+ let!(:prefix) do
11
+ IpFilter.configuration { |c| c.cache_prefix = 'ip_filter_test:' }
12
+ end
13
+
14
+ subject { described_class.new(IpFilter.configuration.cache, prefix) }
15
+
16
+ it { expect respond_to(:reset).with(0).arguments }
17
+ it { expect respond_to(:[]).with(1).arguments }
18
+ it { expect respond_to(:[]=).with(2).arguments }
19
+
20
+ context '#reset' do
21
+ let!(:post_created_ips) do
22
+ IpFilter.search('100.10.220.10')
23
+ IpFilter.search('55.10.220.10')
24
+ IpFilter.search('125.10.220.10')
25
+ IpFilter.search('200.10.220.10')
26
+ end
27
+
28
+ let!(:keys) { IpFilter.configuration.cache.keys('ip_filter_test:*') }
29
+
30
+ it 'should drop all existing cache keys' do
31
+ subject.reset
32
+ expect(
33
+ subject.store.keys("#{prefix}*")
34
+ ).to be_empty
35
+ end
36
+ end
37
+
38
+ context '#[] (getter)' do
39
+ let!(:post_saved_ip) { IpFilter.search('55.10.220.10') }
40
+
41
+ it 'should return result from cache' do
42
+ expected_cache = subject.store.keys("#{prefix}:55.10.220.10")
43
+ expect(expected_cache).to be_empty
44
+ expect(expected_cache).not_to include post_saved_ip
45
+ end
46
+ end
47
+
48
+ context '#[]= (setter)' do
49
+ it 'should return result from cache' do
50
+ subject['55.10.220.10'] = { this: 'is a test' }
51
+ result = subject['55.10.220.10']
52
+
53
+ expect(result.to_h).to eq(this: 'is a test')
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ require 'action_controller'
3
+ require 'ip_filter'
4
+ require 'ip_filter/controller/geo_ip_lookup'
5
+
6
+ class IpController < ::ActionController::Base
7
+ include IpFilter::Controller::GeoIpLookup
8
+ include IpFilter::Request
9
+
10
+ validate_ip
11
+ skip_validate_ip only: [:test_action_skip]
12
+
13
+ def test_action
14
+ render text: 'Testing test output'
15
+ end
16
+
17
+ def test_action_skip
18
+ render text: 'Testing test output'
19
+ end
20
+ end
21
+
22
+ describe IpController do
23
+ context 'ip_validate' do
24
+ before(:each) do
25
+ allow(IpFilter.configuration).to receive(:ip_whitelist) {['127.0.0.1/24']}
26
+ end
27
+
28
+ it 'should validate IP and raise error' do
29
+ expect { action_call(IpController, :test_action, ip: '246.243.3.83')
30
+ }.to raise_error(ArgumentError, /GeoIP/)
31
+ end
32
+
33
+ it 'should validate IP 127.0.0.1 and success' do
34
+ expect {
35
+ action_call(IpController, :test_action, ip: '127.0.0.1')
36
+ }.to_not raise_error
37
+ end
38
+
39
+ it 'should validate IP 127.0.0.254 and success' do
40
+ expect {
41
+ action_call(IpController, :test_action, ip: '127.0.0.254')
42
+ }.to_not raise_error
43
+ end
44
+ end
45
+ context 'skip_ip_validate' do
46
+ before(:each) do
47
+ IpFilter.configuration.ip_whitelist = proc { ['127.0.0.1/24'] }
48
+ end
49
+
50
+ it 'should validate IP and not raise error' do
51
+ expect {
52
+ action_call(IpController, :test_action_skip, ip: '146.243.3.83')
53
+ }.to_not raise_error
54
+ end
55
+ end
56
+ end
Binary file
@@ -0,0 +1,31 @@
1
+ OPEN DATA LICENSE (GeoLite Country and GeoLite City databases)
2
+
3
+ Copyright (c) 2008 MaxMind, Inc. All Rights Reserved.
4
+
5
+ All advertising materials and documentation mentioning features or use of
6
+ this database must display the following acknowledgment:
7
+ "This product includes GeoLite data created by MaxMind, available from
8
+ http://maxmind.com/"
9
+
10
+ Redistribution and use with or without modification, are permitted provided
11
+ that the following conditions are met:
12
+ 1. Redistributions must retain the above copyright notice, this list of
13
+ conditions and the following disclaimer in the documentation and/or other
14
+ materials provided with the distribution.
15
+ 2. All advertising materials and documentation mentioning features or use of
16
+ this database must display the following acknowledgement:
17
+ "This product includes GeoLite data created by MaxMind, available from
18
+ http://maxmind.com/"
19
+ 3. "MaxMind" may not be used to endorse or promote products derived from this
20
+ database without specific prior written permission.
21
+
22
+ THIS DATABASE IS PROVIDED BY MAXMIND, INC ``AS IS'' AND ANY
23
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
+ DISCLAIMED. IN NO EVENT SHALL MAXMIND BE LIABLE FOR ANY
26
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
+ DATABASE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Binary file
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe IpFilter do
4
+ context 'Methods' do
5
+ context '#ip_address?' do
6
+ it 'should success on IP range ' do
7
+ expect(
8
+ described_class.send(:ip_address?, '1.2.3.4/1')
9
+ ).to be_truthy
10
+ end
11
+
12
+ it 'should success on IP ' do
13
+ expect(
14
+ described_class.send(:ip_address?, '1.2.3.4')
15
+ ).to be_truthy
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ require 'ip_filter'
2
+ require 'ip_filter/providers/max_mind'
3
+
4
+ describe IpFilter::Providers::MaxMind do
5
+ subject { IpFilter::Providers::MaxMind.new }
6
+
7
+ it { expect respond_to(:update!).with(0).argument }
8
+ it { expect respond_to(:config).with(0).argument }
9
+ it { expect respond_to(:folder).with(0).argument }
10
+ it { expect respond_to(:refresh_file_list).with(0).argument }
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'ip_filter'
2
+ require 'ip_filter/providers/s3'
3
+
4
+ describe IpFilter::Providers::S3 do
5
+ it { expect respond_to(:new).with(0).argument }
6
+ it { expect respond_to(:upload!).with(0).argument }
7
+ it { expect respond_to(:create_bucket).with(0).argument }
8
+ it { expect respond_to(:download!).with(0).argument }
9
+ it { expect respond_to(:download!).with(1).argument }
10
+ it { expect respond_to(:refresh_file_list).with(0).argument }
11
+ end
@@ -0,0 +1,40 @@
1
+ ENV['RAILS_ENV'] ||= 'test'
2
+
3
+ # require File.expand_path('../../rails_app/config/environment', __FILE__)
4
+ require 'rails/all'
5
+ require 'rspec'
6
+ require 'rspec/rails'
7
+ require 'ip_filter'
8
+
9
+ # Load support helpers
10
+ require 'support/enable_dallistore_cache'
11
+ require 'support/enable_redis_cache'
12
+
13
+ # Configure RSpec
14
+ RSpec.configure do |config|
15
+ # config.include Rack::Test::Methods
16
+ end
17
+
18
+ # Configure IP filter gem
19
+ IpFilter.configure do |config|
20
+ config.data_folder = File.expand_path('../fixtures', __FILE__)
21
+ config.geo_ip_dat = File.expand_path('../fixtures/GeoIP.dat', __FILE__)
22
+ config.ip_code_type = 'country_code2'
23
+ config.ip_codes = ['country_code2']
24
+ config.ip_whitelist = ['127.0.0.1/24']
25
+ config.cache = nil
26
+ config.allow_loopback = false
27
+ config.ip_exception = Proc.new {
28
+ raise ArgumentError, ('GeoIP: IP is not in whitelist')
29
+ }
30
+ end
31
+
32
+ # Stub Rack::Request and preload IpFilter::Request
33
+ # to get IP location as a request's attribute.
34
+ Rack::Request.send :include, IpFilter::Request
35
+
36
+ def action_call(controller, action, opts)
37
+ env = Rack::MockRequest.env_for('/', 'REMOTE_ADDR' => opts[:ip] || '127.0.0.1')
38
+ status, headers, body = controller.action(action).call(env)
39
+ ActionDispatch::TestResponse.new(status, headers, body)
40
+ end
@@ -0,0 +1,15 @@
1
+ require 'dalli'
2
+
3
+ module EnableDallistoreCache
4
+ def activate_dallistore!
5
+ let(:cache) { Dalli::Client.new }
6
+
7
+ before do
8
+ allow(IpFilter.configuration).to receive_messages(cache: cache)
9
+ end
10
+
11
+ after do
12
+ allow(IpFilter.configuration).to receive_messages(cache: nil)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'fakeredis'
2
+
3
+ module EnableRedisCache
4
+ def activate_redis!
5
+ let(:cache) { Redis.new }
6
+
7
+ before do
8
+ allow(IpFilter.configuration).to receive(:cache) { cache }
9
+ end
10
+
11
+ after do
12
+ allow(IpFilter.configuration).to receive(:cache) { nil }
13
+ end
14
+ end
15
+ end