maxmind-geoip2 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +12 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +38 -0
  5. data/LICENSE-APACHE +202 -0
  6. data/LICENSE-MIT +17 -0
  7. data/README.dev.md +4 -0
  8. data/README.md +274 -0
  9. data/Rakefile +14 -0
  10. data/lib/maxmind/geoip2.rb +3 -0
  11. data/lib/maxmind/geoip2/errors.rb +7 -0
  12. data/lib/maxmind/geoip2/model/abstract.rb +27 -0
  13. data/lib/maxmind/geoip2/model/anonymous_ip.rb +63 -0
  14. data/lib/maxmind/geoip2/model/asn.rb +39 -0
  15. data/lib/maxmind/geoip2/model/city.rb +75 -0
  16. data/lib/maxmind/geoip2/model/connection_type.rb +32 -0
  17. data/lib/maxmind/geoip2/model/country.rb +63 -0
  18. data/lib/maxmind/geoip2/model/domain.rb +32 -0
  19. data/lib/maxmind/geoip2/model/enterprise.rb +15 -0
  20. data/lib/maxmind/geoip2/model/isp.rb +53 -0
  21. data/lib/maxmind/geoip2/reader.rb +277 -0
  22. data/lib/maxmind/geoip2/record/abstract.rb +22 -0
  23. data/lib/maxmind/geoip2/record/city.rb +38 -0
  24. data/lib/maxmind/geoip2/record/continent.rb +37 -0
  25. data/lib/maxmind/geoip2/record/country.rb +54 -0
  26. data/lib/maxmind/geoip2/record/location.rb +73 -0
  27. data/lib/maxmind/geoip2/record/place.rb +28 -0
  28. data/lib/maxmind/geoip2/record/postal.rb +30 -0
  29. data/lib/maxmind/geoip2/record/represented_country.rb +23 -0
  30. data/lib/maxmind/geoip2/record/subdivision.rb +48 -0
  31. data/lib/maxmind/geoip2/record/traits.rb +200 -0
  32. data/maxmind-geoip2.gemspec +24 -0
  33. data/test/data/LICENSE +4 -0
  34. data/test/data/MaxMind-DB-spec.md +570 -0
  35. data/test/data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  36. data/test/data/README.md +4 -0
  37. data/test/data/bad-data/README.md +7 -0
  38. data/test/data/bad-data/libmaxminddb/libmaxminddb-offset-integer-overflow.mmdb +0 -0
  39. data/test/data/bad-data/maxminddb-golang/cyclic-data-structure.mmdb +0 -0
  40. data/test/data/bad-data/maxminddb-golang/invalid-bytes-length.mmdb +1 -0
  41. data/test/data/bad-data/maxminddb-golang/invalid-data-record-offset.mmdb +0 -0
  42. data/test/data/bad-data/maxminddb-golang/invalid-map-key-length.mmdb +0 -0
  43. data/test/data/bad-data/maxminddb-golang/invalid-string-length.mmdb +1 -0
  44. data/test/data/bad-data/maxminddb-golang/metadata-is-an-uint128.mmdb +1 -0
  45. data/test/data/bad-data/maxminddb-golang/unexpected-bytes.mmdb +0 -0
  46. data/test/data/perltidyrc +12 -0
  47. data/test/data/source-data/GeoIP2-Anonymous-IP-Test.json +48 -0
  48. data/test/data/source-data/GeoIP2-City-Test.json +12852 -0
  49. data/test/data/source-data/GeoIP2-Connection-Type-Test.json +102 -0
  50. data/test/data/source-data/GeoIP2-Country-Test.json +15916 -0
  51. data/test/data/source-data/GeoIP2-DensityIncome-Test.json +14 -0
  52. data/test/data/source-data/GeoIP2-Domain-Test.json +452 -0
  53. data/test/data/source-data/GeoIP2-Enterprise-Test.json +687 -0
  54. data/test/data/source-data/GeoIP2-ISP-Test.json +12593 -0
  55. data/test/data/source-data/GeoIP2-Precision-Enterprise-Test.json +2061 -0
  56. data/test/data/source-data/GeoIP2-Static-IP-Score-Test.json +2132 -0
  57. data/test/data/source-data/GeoIP2-User-Count-Test.json +2837 -0
  58. data/test/data/source-data/GeoLite2-ASN-Test.json +37 -0
  59. data/test/data/source-data/README +15 -0
  60. data/test/data/test-data/GeoIP2-Anonymous-IP-Test.mmdb +0 -0
  61. data/test/data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb +0 -0
  62. data/test/data/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb +0 -0
  63. data/test/data/test-data/GeoIP2-City-Test.mmdb +0 -0
  64. data/test/data/test-data/GeoIP2-Connection-Type-Test.mmdb +0 -0
  65. data/test/data/test-data/GeoIP2-Country-Test.mmdb +0 -0
  66. data/test/data/test-data/GeoIP2-DensityIncome-Test.mmdb +0 -0
  67. data/test/data/test-data/GeoIP2-Domain-Test.mmdb +0 -0
  68. data/test/data/test-data/GeoIP2-Enterprise-Test.mmdb +0 -0
  69. data/test/data/test-data/GeoIP2-ISP-Test.mmdb +0 -0
  70. data/test/data/test-data/GeoIP2-Precision-Enterprise-Test.mmdb +0 -0
  71. data/test/data/test-data/GeoIP2-Static-IP-Score-Test.mmdb +0 -0
  72. data/test/data/test-data/GeoIP2-User-Count-Test.mmdb +0 -0
  73. data/test/data/test-data/GeoLite2-ASN-Test.mmdb +0 -0
  74. data/test/data/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb +0 -0
  75. data/test/data/test-data/MaxMind-DB-string-value-entries.mmdb +0 -0
  76. data/test/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb +0 -0
  77. data/test/data/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb +0 -0
  78. data/test/data/test-data/MaxMind-DB-test-decoder.mmdb +0 -0
  79. data/test/data/test-data/MaxMind-DB-test-ipv4-24.mmdb +0 -0
  80. data/test/data/test-data/MaxMind-DB-test-ipv4-28.mmdb +0 -0
  81. data/test/data/test-data/MaxMind-DB-test-ipv4-32.mmdb +0 -0
  82. data/test/data/test-data/MaxMind-DB-test-ipv6-24.mmdb +0 -0
  83. data/test/data/test-data/MaxMind-DB-test-ipv6-28.mmdb +0 -0
  84. data/test/data/test-data/MaxMind-DB-test-ipv6-32.mmdb +0 -0
  85. data/test/data/test-data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  86. data/test/data/test-data/MaxMind-DB-test-mixed-24.mmdb +0 -0
  87. data/test/data/test-data/MaxMind-DB-test-mixed-28.mmdb +0 -0
  88. data/test/data/test-data/MaxMind-DB-test-mixed-32.mmdb +0 -0
  89. data/test/data/test-data/MaxMind-DB-test-nested.mmdb +0 -0
  90. data/test/data/test-data/README.md +26 -0
  91. data/test/data/test-data/maps-with-pointers.raw +0 -0
  92. data/test/data/test-data/write-test-data.pl +641 -0
  93. data/test/data/tidyall.ini +5 -0
  94. data/test/test_model_country.rb +80 -0
  95. data/test/test_model_names.rb +47 -0
  96. data/test/test_reader.rb +459 -0
  97. metadata +159 -0
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake/testtask'
4
+ require 'rubocop/rake_task'
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs << 'test'
8
+ end
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ desc 'Run tests and RuboCop'
13
+ task default: :test
14
+ task default: :rubocop
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/reader'
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MaxMind::GeoIP2
4
+ # An AddressNotFoundError means the IP address was not found in the database.
5
+ class AddressNotFoundError < RuntimeError
6
+ end
7
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # @!visibility private
7
+ class Abstract
8
+ def initialize(record)
9
+ @record = record
10
+
11
+ ip = IPAddr.new(record['ip_address']).mask(record['prefix_length'])
12
+ record['network'] = format('%s/%d', ip.to_s, record['prefix_length'])
13
+ end
14
+
15
+ protected
16
+
17
+ def get(key)
18
+ if @record.nil? || !@record.key?(key)
19
+ return false if key.start_with?('is_')
20
+
21
+ return nil
22
+ end
23
+
24
+ @record[key]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the Anonymous IP database.
7
+ class AnonymousIP < Abstract
8
+ # This is true if the IP address belongs to any sort of anonymous network.
9
+ #
10
+ # @return [Boolean]
11
+ def anonymous?
12
+ get('is_anonymous')
13
+ end
14
+
15
+ # This is true if the IP address is registered to an anonymous VPN
16
+ # provider. If a VPN provider does not register subnets under names
17
+ # associated with them, we will likely only flag their IP ranges using the
18
+ # is_hosting_provider attribute.
19
+ #
20
+ # @return [Boolean]
21
+ def anonymous_vpn?
22
+ get('is_anonymous_vpn')
23
+ end
24
+
25
+ # This is true if the IP address belongs to a hosting or VPN provider (see
26
+ # description of the is_anonymous_vpn attribute).
27
+ #
28
+ # @return [Boolean]
29
+ def hosting_provider?
30
+ get('is_hosting_provider')
31
+ end
32
+
33
+ # The IP address that the data in the model is for.
34
+ #
35
+ # @return [String]
36
+ def ip_address
37
+ get('ip_address')
38
+ end
39
+
40
+ # The network in CIDR notation associated with the record. In particular,
41
+ # this is the largest network where all of the fields besides ip_address
42
+ # have the same value.
43
+ #
44
+ # @return [String]
45
+ def network
46
+ get('network')
47
+ end
48
+
49
+ # This is true if the IP address belongs to a public proxy.
50
+ #
51
+ # @return [Boolean]
52
+ def public_proxy?
53
+ get('is_public_proxy')
54
+ end
55
+
56
+ # This is true if the IP address is a Tor exit node.
57
+ #
58
+ # @return [Boolean]
59
+ def tor_exit_node?
60
+ get('is_tor_exit_node')
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the GeoLite2 ASN database.
7
+ class ASN < Abstract
8
+ # The autonomous system number associated with the IP address.
9
+ #
10
+ # @return [Integer, nil]
11
+ def autonomous_system_number
12
+ get('autonomous_system_number')
13
+ end
14
+
15
+ # The organization associated with the registered autonomous system number
16
+ # for the IP address.
17
+ #
18
+ # @return [String, nil]
19
+ def autonomous_system_organization
20
+ get('autonomous_system_organization')
21
+ end
22
+
23
+ # The IP address that the data in the model is for.
24
+ #
25
+ # @return [String]
26
+ def ip_address
27
+ get('ip_address')
28
+ end
29
+
30
+ # The network in CIDR notation associated with the record. In particular,
31
+ # this is the largest network where all of the fields besides ip_address
32
+ # have the same value.
33
+ #
34
+ # @return [String]
35
+ def network
36
+ get('network')
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/country'
4
+ require 'maxmind/geoip2/record/city'
5
+ require 'maxmind/geoip2/record/location'
6
+ require 'maxmind/geoip2/record/postal'
7
+ require 'maxmind/geoip2/record/subdivision'
8
+
9
+ module MaxMind::GeoIP2::Model
10
+ # Model class for the data returned by the GeoIP2 City web service and
11
+ # database. It is also used for GeoLite2 City lookups.
12
+ #
13
+ # The only difference between the City and Insights model classes is which
14
+ # fields in each record may be populated. See
15
+ # https://dev.maxmind.com/geoip/geoip2/web-services for more details.
16
+ #
17
+ # See {MaxMind::GeoIP2::Model::Country} for inherited methods.
18
+ class City < Country
19
+ # City data for the IP address.
20
+ #
21
+ # @return [MaxMind::GeoIP2::Record::City]
22
+ attr_reader :city
23
+
24
+ # Location data for the IP address.
25
+ #
26
+ # @return [MaxMind::GeoIP2::Record::Location]
27
+ attr_reader :location
28
+
29
+ # Postal data for the IP address.
30
+ #
31
+ # @return [MaxMind::GeoIP2::Record::Postal]
32
+ attr_reader :postal
33
+
34
+ # The country subdivisions for the IP address.
35
+ #
36
+ # The number and type of subdivisions varies by country, but a subdivision
37
+ # is typically a state, province, country, etc. Subdivisions are ordered
38
+ # from most general (largest) to most specific (smallest).
39
+ #
40
+ # If the response did not contain any subdivisions, this attribute will be
41
+ # an empty array.
42
+ #
43
+ # @return [Array<MaxMind::GeoIP2::Record::Subdivision>]
44
+ attr_reader :subdivisions
45
+
46
+ # @!visibility private
47
+ def initialize(record, locales)
48
+ super(record, locales)
49
+ @city = MaxMind::GeoIP2::Record::City.new(record['city'], locales)
50
+ @location = MaxMind::GeoIP2::Record::Location.new(record['location'])
51
+ @postal = MaxMind::GeoIP2::Record::Postal.new(record['postal'])
52
+ @subdivisions = create_subdivisions(record['subdivisions'], locales)
53
+ end
54
+
55
+ # The most specific subdivision returned.
56
+ #
57
+ # If the response did not contain any subdivisions, this method returns
58
+ # nil.
59
+ #
60
+ # @return [MaxMind::GeoIP2::Record::Subdivision, nil]
61
+ def most_specific_subdivision
62
+ @subdivisions.last
63
+ end
64
+
65
+ private
66
+
67
+ def create_subdivisions(subdivisions, locales)
68
+ return [] if subdivisions.nil?
69
+
70
+ subdivisions.map do |s|
71
+ MaxMind::GeoIP2::Record::Subdivision.new(s, locales)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the GeoIP2 Connection Type database.
7
+ class ConnectionType < Abstract
8
+ # The connection type may take the following values: "Dialup", "Cable/DSL",
9
+ # "Corporate", "Cellular". Additional values may be added in the future.
10
+ #
11
+ # @return [String, nil]
12
+ def connection_type
13
+ get('connection_type')
14
+ end
15
+
16
+ # The IP address that the data in the model is for.
17
+ #
18
+ # @return [String]
19
+ def ip_address
20
+ get('ip_address')
21
+ end
22
+
23
+ # The network in CIDR notation associated with the record. In particular,
24
+ # this is the largest network where all of the fields besides ip_address
25
+ # have the same value.
26
+ #
27
+ # @return [String]
28
+ def network
29
+ get('network')
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/record/continent'
4
+ require 'maxmind/geoip2/record/country'
5
+ require 'maxmind/geoip2/record/represented_country'
6
+ require 'maxmind/geoip2/record/traits'
7
+
8
+ module MaxMind::GeoIP2::Model
9
+ # Model class for the data returned by the GeoIP2 Country web service and
10
+ # database. It is also used for GeoLite2 Country lookups.
11
+ class Country
12
+ # Continent data for the IP address.
13
+ #
14
+ # @return [MaxMind::GeoIP2::Record::Continent]
15
+ attr_reader :continent
16
+
17
+ # Country data for the IP address. This object represents the country where
18
+ # MaxMind believes the end user is located.
19
+ #
20
+ # @return [MaxMind::GeoIP2::Record::Country]
21
+ attr_reader :country
22
+
23
+ # Registered country data for the IP address. This record represents the
24
+ # country where the ISP has registered a given IP block and may differ from
25
+ # the user's country.
26
+ #
27
+ # @return [MaxMind::GeoIP2::Record::Country]
28
+ attr_reader :registered_country
29
+
30
+ # Represented country data for the IP address. The represented country is
31
+ # used for things like military bases. It is only present when the
32
+ # represented country differs from the country.
33
+ #
34
+ # @return [MaxMind::GeoIP2::Record::RepresentedCountry]
35
+ attr_reader :represented_country
36
+
37
+ # Data for the traits of the IP address.
38
+ #
39
+ # @return [MaxMind::GeoIP2::Record::Traits]
40
+ attr_reader :traits
41
+
42
+ # @!visibility private
43
+ def initialize(record, locales)
44
+ @continent = MaxMind::GeoIP2::Record::Continent.new(
45
+ record['continent'],
46
+ locales,
47
+ )
48
+ @country = MaxMind::GeoIP2::Record::Country.new(
49
+ record['country'],
50
+ locales,
51
+ )
52
+ @registered_country = MaxMind::GeoIP2::Record::Country.new(
53
+ record['registered_country'],
54
+ locales,
55
+ )
56
+ @represented_country = MaxMind::GeoIP2::Record::RepresentedCountry.new(
57
+ record['represented_country'],
58
+ locales,
59
+ )
60
+ @traits = MaxMind::GeoIP2::Record::Traits.new(record['traits'])
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the GeoIP2 Domain database.
7
+ class Domain < Abstract
8
+ # The second level domain associated with the IP address. This will be
9
+ # something like "example.com" or "example.co.uk", not "foo.example.com".
10
+ #
11
+ # @return [String, nil]
12
+ def domain
13
+ get('domain')
14
+ end
15
+
16
+ # The IP address that the data in the model is for.
17
+ #
18
+ # @return [String]
19
+ def ip_address
20
+ get('ip_address')
21
+ end
22
+
23
+ # The network in CIDR notation associated with the record. In particular,
24
+ # this is the largest network where all of the fields besides ip_address
25
+ # have the same value.
26
+ #
27
+ # @return [String]
28
+ def network
29
+ get('network')
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/city'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the data returned by GeoIP2 Enterprise database lookups.
7
+ #
8
+ # The only difference between the City and Insights model classes is which
9
+ # fields in each record may be populated. See
10
+ # https://dev.maxmind.com/geoip/geoip2/web-services for more details.
11
+ #
12
+ # See {MaxMind::GeoIP2::Model::City} for inherited methods.
13
+ class Enterprise < City
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind::GeoIP2::Model
6
+ # Model class for the GeoIP2 ISP database.
7
+ class ISP < Abstract
8
+ # The autonomous system number associated with the IP address.
9
+ #
10
+ # @return [Integer, nil]
11
+ def autonomous_system_number
12
+ get('autonomous_system_number')
13
+ end
14
+
15
+ # The organization associated with the registered autonomous system number
16
+ # for the IP address.
17
+ #
18
+ # @return [String, nil]
19
+ def autonomous_system_organization
20
+ get('autonomous_system_organization')
21
+ end
22
+
23
+ # The IP address that the data in the model is for.
24
+ #
25
+ # @return [String]
26
+ def ip_address
27
+ get('ip_address')
28
+ end
29
+
30
+ # The name of the ISP associated with the IP address.
31
+ #
32
+ # @return [String, nil]
33
+ def isp
34
+ get('isp')
35
+ end
36
+
37
+ # The network in CIDR notation associated with the record. In particular,
38
+ # this is the largest network where all of the fields besides ip_address
39
+ # have the same value.
40
+ #
41
+ # @return [String]
42
+ def network
43
+ get('network')
44
+ end
45
+
46
+ # The name of the organization associated with the IP address.
47
+ #
48
+ # @return [String, nil]
49
+ def organization
50
+ get('organization')
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,277 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/db'
4
+ require 'maxmind/geoip2/errors'
5
+ require 'maxmind/geoip2/model/anonymous_ip'
6
+ require 'maxmind/geoip2/model/asn'
7
+ require 'maxmind/geoip2/model/city'
8
+ require 'maxmind/geoip2/model/connection_type'
9
+ require 'maxmind/geoip2/model/country'
10
+ require 'maxmind/geoip2/model/domain'
11
+ require 'maxmind/geoip2/model/enterprise'
12
+ require 'maxmind/geoip2/model/isp'
13
+
14
+ module MaxMind::GeoIP2
15
+ # Reader is a reader for the GeoIP2/GeoLite2 database format. IP addresses
16
+ # can be looked up using the database specific methods.
17
+ #
18
+ # == Example
19
+ #
20
+ # require 'maxmind/geoip2'
21
+ #
22
+ # reader = MaxMind::GeoIP2::Reader.new('GeoIP2-Country.mmdb')
23
+ #
24
+ # record = reader.country('1.2.3.4')
25
+ # puts record.country.iso_code
26
+ #
27
+ # reader.close
28
+ class Reader
29
+ # Create a Reader for looking up IP addresses in a GeoIP2/GeoLite2 database
30
+ # file.
31
+ #
32
+ # If you're performing multiple lookups, it's most efficient to create one
33
+ # Reader and reuse it.
34
+ #
35
+ # Once created, the Reader is safe to use for lookups from multiple
36
+ # threads. It is safe to use after forking only if you use
37
+ # MaxMind::DB::MODE_MEMORY or if your version of Ruby supports IO#pread.
38
+ #
39
+ # @param database [String] a path to a GeoIP2/GeoLite2 database file.
40
+ #
41
+ # @param locales [Array<String>] a list of locale codes to use in the name
42
+ # property from most preferred to least preferred.
43
+ #
44
+ # @param options [Hash<Symbol, Symbol>] options controlling the behavior of
45
+ # the Reader.
46
+ #
47
+ # @option options [Symbol] :mode Defines how to open the database. It may
48
+ # be one of MaxMind::DB::MODE_AUTO, MaxMind::DB::MODE_FILE, or
49
+ # MaxMind::DB::MODE_MEMORY. If you don't provide one, the Reader uses
50
+ # MaxMind::DB::MODE_AUTO. Refer to the definition of those constants in
51
+ # MaxMind::DB for an explanation of their meaning.
52
+ #
53
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database is corrupt or
54
+ # invalid.
55
+ #
56
+ # @raise [ArgumentError] if the mode is invalid.
57
+ def initialize(database, locales = ['en'], options = {})
58
+ @reader = MaxMind::DB.new(database, options)
59
+ @type = @reader.metadata.database_type
60
+ locales = ['en'] if locales.empty?
61
+ @locales = locales
62
+ end
63
+
64
+ # Look up the IP address in the database.
65
+ #
66
+ # @param ip_address [String] a string in the standard notation. It may be
67
+ # IPv4 or IPv6.
68
+ #
69
+ # @return [MaxMind::GeoIP2::Model::AnonymousIP]
70
+ #
71
+ # @raise [ArgumentError] if used against a non-Anonymous IP database or if
72
+ # you attempt to look up an IPv6 address in an IPv4 only database.
73
+ #
74
+ # @raise [AddressNotFoundError] if the IP address is not found in the
75
+ # database.
76
+ #
77
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
78
+ # corrupt.
79
+ def anonymous_ip(ip_address)
80
+ flat_model_for(
81
+ Model::AnonymousIP,
82
+ 'anonymous_ip',
83
+ 'GeoIP2-Anonymous-IP',
84
+ ip_address,
85
+ )
86
+ end
87
+
88
+ # Look up the IP address in an ASN database.
89
+ #
90
+ # @param ip_address [String] a string in the standard notation. It may be
91
+ # IPv4 or IPv6.
92
+ #
93
+ # @return [MaxMind::GeoIP2::Model::ASN]
94
+ #
95
+ # @raise [ArgumentError] if used against a non-ASN database or if you
96
+ # attempt to look up an IPv6 address in an IPv4 only database.
97
+ #
98
+ # @raise [AddressNotFoundError] if the IP address is not found in the
99
+ # database.
100
+ #
101
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
102
+ # corrupt.
103
+ def asn(ip_address)
104
+ flat_model_for(Model::ASN, 'asn', 'GeoLite2-ASN', ip_address)
105
+ end
106
+
107
+ # Look up the IP address in a City database.
108
+ #
109
+ # @param ip_address [String] a string in the standard notation. It may be
110
+ # IPv4 or IPv6.
111
+ #
112
+ # @return [MaxMind::GeoIP2::Model::City]
113
+ #
114
+ # @raise [ArgumentError] if used against a non-City database or if you
115
+ # attempt to look up an IPv6 address in an IPv4 only database.
116
+ #
117
+ # @raise [AddressNotFoundError] if the IP address is not found in the
118
+ # database.
119
+ #
120
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
121
+ # corrupt.
122
+ def city(ip_address)
123
+ model_for(Model::City, 'city', 'City', ip_address)
124
+ end
125
+
126
+ # Look up the IP address in a Connection Type database.
127
+ #
128
+ # @param ip_address [String] a string in the standard notation. It may be
129
+ # IPv4 or IPv6.
130
+ #
131
+ # @return [MaxMind::GeoIP2::Model::ConnectionType]
132
+ #
133
+ # @raise [ArgumentError] if used against a non-Connection Type database or if
134
+ # you attempt to look up an IPv6 address in an IPv4 only database.
135
+ #
136
+ # @raise [AddressNotFoundError] if the IP address is not found in the
137
+ # database.
138
+ #
139
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
140
+ # corrupt.
141
+ def connection_type(ip_address)
142
+ flat_model_for(
143
+ Model::ConnectionType,
144
+ 'connection_type',
145
+ 'GeoIP2-Connection-Type',
146
+ ip_address,
147
+ )
148
+ end
149
+
150
+ # Look up the IP address in a Country database.
151
+ #
152
+ # @param ip_address [String] a string in the standard notation. It may be
153
+ # IPv4 or IPv6.
154
+ #
155
+ # @return [MaxMind::GeoIP2::Model::Country]
156
+ #
157
+ # @raise [ArgumentError] if used against a non-Country database or if you
158
+ # attempt to look up an IPv6 address in an IPv4 only database.
159
+ #
160
+ # @raise [AddressNotFoundError] if the IP address is not found in the
161
+ # database.
162
+ #
163
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
164
+ # corrupt.
165
+ def country(ip_address)
166
+ model_for(Model::Country, 'country', 'Country', ip_address)
167
+ end
168
+
169
+ # Look up the IP address in a Domain database.
170
+ #
171
+ # @param ip_address [String] a string in the standard notation. It may be
172
+ # IPv4 or IPv6.
173
+ #
174
+ # @return [MaxMind::GeoIP2::Model::Domain]
175
+ #
176
+ # @raise [ArgumentError] if used against a non-Domain database or if you
177
+ # attempt to look up an IPv6 address in an IPv4 only database.
178
+ #
179
+ # @raise [AddressNotFoundError] if the IP address is not found in the
180
+ # database.
181
+ #
182
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
183
+ # corrupt.
184
+ def domain(ip_address)
185
+ flat_model_for(Model::Domain, 'domain', 'GeoIP2-Domain', ip_address)
186
+ end
187
+
188
+ # Look up the IP address in an Enterprise database.
189
+ #
190
+ # @param ip_address [String] a string in the standard notation. It may be
191
+ # IPv4 or IPv6.
192
+ #
193
+ # @return [MaxMind::GeoIP2::Model::Enterprise]
194
+ #
195
+ # @raise [ArgumentError] if used against a non-Enterprise database or if
196
+ # you attempt to look up an IPv6 address in an IPv4 only database.
197
+ #
198
+ # @raise [AddressNotFoundError] if the IP address is not found in the
199
+ # database.
200
+ #
201
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
202
+ # corrupt.
203
+ def enterprise(ip_address)
204
+ model_for(Model::Enterprise, 'enterprise', 'Enterprise', ip_address)
205
+ end
206
+
207
+ # Look up the IP address in an ISP database.
208
+ #
209
+ # @param ip_address [String] a string in the standard notation. It may be
210
+ # IPv4 or IPv6.
211
+ #
212
+ # @return [MaxMind::GeoIP2::Model::ISP]
213
+ #
214
+ # @raise [ArgumentError] if used against a non-ISP database or if you
215
+ # attempt to look up an IPv6 address in an IPv4 only database.
216
+ #
217
+ # @raise [AddressNotFoundError] if the IP address is not found in the
218
+ # database.
219
+ #
220
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database appears
221
+ # corrupt.
222
+ def isp(ip_address)
223
+ flat_model_for(Model::ISP, 'isp', 'GeoIP2-ISP', ip_address)
224
+ end
225
+
226
+ # Return the metadata associated with the database.
227
+ #
228
+ # @return [MaxMind::DB::Metadata]
229
+ def metadata
230
+ @reader.metadata
231
+ end
232
+
233
+ # Close the Reader and return resources to the system.
234
+ #
235
+ # @return [void]
236
+ def close
237
+ @reader.close
238
+ end
239
+
240
+ private
241
+
242
+ def model_for(model_class, method, type, ip_address)
243
+ record, prefix_length = get_record(method, type, ip_address)
244
+
245
+ record['traits'] = {} if !record.key?('traits')
246
+ record['traits']['ip_address'] = ip_address
247
+ record['traits']['prefix_length'] = prefix_length
248
+
249
+ model_class.new(record, @locales)
250
+ end
251
+
252
+ def get_record(method, type, ip_address)
253
+ if !@type.include?(type)
254
+ raise ArgumentError,
255
+ "The #{method} method cannot be used with the #{@type} database."
256
+ end
257
+
258
+ record, prefix_length = @reader.get_with_prefix_length(ip_address)
259
+
260
+ if record.nil?
261
+ raise AddressNotFoundError,
262
+ "The address #{ip_address} is not in the database."
263
+ end
264
+
265
+ [record, prefix_length]
266
+ end
267
+
268
+ def flat_model_for(model_class, method, type, ip_address)
269
+ record, prefix_length = get_record(method, type, ip_address)
270
+
271
+ record['ip_address'] = ip_address
272
+ record['prefix_length'] = prefix_length
273
+
274
+ model_class.new(record)
275
+ end
276
+ end
277
+ end