maxmind-geoip2 0.0.1 → 0.5.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 (99) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +30 -0
  3. data/Gemfile +1 -5
  4. data/README.md +121 -0
  5. data/lib/maxmind/geoip2.rb +1 -13
  6. data/lib/maxmind/geoip2/client.rb +328 -0
  7. data/lib/maxmind/geoip2/errors.rb +37 -3
  8. data/lib/maxmind/geoip2/model/abstract.rb +31 -0
  9. data/lib/maxmind/geoip2/model/anonymous_ip.rb +75 -0
  10. data/lib/maxmind/geoip2/model/asn.rb +43 -0
  11. data/lib/maxmind/geoip2/model/city.rb +63 -44
  12. data/lib/maxmind/geoip2/model/connection_type.rb +36 -0
  13. data/lib/maxmind/geoip2/model/country.rb +64 -45
  14. data/lib/maxmind/geoip2/model/domain.rb +36 -0
  15. data/lib/maxmind/geoip2/model/enterprise.rb +13 -9
  16. data/lib/maxmind/geoip2/model/insights.rb +18 -0
  17. data/lib/maxmind/geoip2/model/isp.rb +57 -0
  18. data/lib/maxmind/geoip2/reader.rb +250 -131
  19. data/lib/maxmind/geoip2/record/abstract.rb +17 -12
  20. data/lib/maxmind/geoip2/record/city.rb +33 -24
  21. data/lib/maxmind/geoip2/record/continent.rb +32 -23
  22. data/lib/maxmind/geoip2/record/country.rb +47 -34
  23. data/lib/maxmind/geoip2/record/location.rb +64 -50
  24. data/lib/maxmind/geoip2/record/maxmind.rb +21 -0
  25. data/lib/maxmind/geoip2/record/place.rb +22 -16
  26. data/lib/maxmind/geoip2/record/postal.rb +26 -18
  27. data/lib/maxmind/geoip2/record/represented_country.rb +20 -14
  28. data/lib/maxmind/geoip2/record/subdivision.rb +42 -34
  29. data/lib/maxmind/geoip2/record/traits.rb +204 -160
  30. data/maxmind-geoip2.gemspec +12 -2
  31. data/test/data/LICENSE +4 -0
  32. data/test/data/MaxMind-DB-spec.md +570 -0
  33. data/test/data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  34. data/test/data/README.md +4 -0
  35. data/test/data/bad-data/README.md +7 -0
  36. data/test/data/bad-data/libmaxminddb/libmaxminddb-offset-integer-overflow.mmdb +0 -0
  37. data/test/data/bad-data/maxminddb-golang/cyclic-data-structure.mmdb +0 -0
  38. data/test/data/bad-data/maxminddb-golang/invalid-bytes-length.mmdb +1 -0
  39. data/test/data/bad-data/maxminddb-golang/invalid-data-record-offset.mmdb +0 -0
  40. data/test/data/bad-data/maxminddb-golang/invalid-map-key-length.mmdb +0 -0
  41. data/test/data/bad-data/maxminddb-golang/invalid-string-length.mmdb +1 -0
  42. data/test/data/bad-data/maxminddb-golang/metadata-is-an-uint128.mmdb +1 -0
  43. data/test/data/bad-data/maxminddb-golang/unexpected-bytes.mmdb +0 -0
  44. data/test/data/bad-data/maxminddb-python/bad-unicode-in-map-key.mmdb +0 -0
  45. data/test/data/perltidyrc +12 -0
  46. data/test/data/source-data/GeoIP2-Anonymous-IP-Test.json +49 -0
  47. data/test/data/source-data/GeoIP2-City-Test.json +12852 -0
  48. data/test/data/source-data/GeoIP2-Connection-Type-Test.json +102 -0
  49. data/test/data/source-data/GeoIP2-Country-Test.json +15916 -0
  50. data/test/data/source-data/GeoIP2-DensityIncome-Test.json +14 -0
  51. data/test/data/source-data/GeoIP2-Domain-Test.json +452 -0
  52. data/test/data/source-data/GeoIP2-Enterprise-Test.json +687 -0
  53. data/test/data/source-data/GeoIP2-ISP-Test.json +12595 -0
  54. data/test/data/source-data/GeoIP2-Precision-Enterprise-Test.json +2148 -0
  55. data/test/data/source-data/GeoIP2-Static-IP-Score-Test.json +2132 -0
  56. data/test/data/source-data/GeoIP2-User-Count-Test.json +2837 -0
  57. data/test/data/source-data/GeoLite2-ASN-Test.json +37 -0
  58. data/test/data/source-data/README +15 -0
  59. data/test/data/test-data/GeoIP2-Anonymous-IP-Test.mmdb +0 -0
  60. data/test/data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb +0 -0
  61. data/test/data/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb +0 -0
  62. data/test/data/test-data/GeoIP2-City-Test.mmdb +0 -0
  63. data/test/data/test-data/GeoIP2-Connection-Type-Test.mmdb +0 -0
  64. data/test/data/test-data/GeoIP2-Country-Test.mmdb +0 -0
  65. data/test/data/test-data/GeoIP2-DensityIncome-Test.mmdb +0 -0
  66. data/test/data/test-data/GeoIP2-Domain-Test.mmdb +0 -0
  67. data/test/data/test-data/GeoIP2-Enterprise-Test.mmdb +0 -0
  68. data/test/data/test-data/GeoIP2-ISP-Test.mmdb +0 -0
  69. data/test/data/test-data/GeoIP2-Precision-Enterprise-Test.mmdb +0 -0
  70. data/test/data/test-data/GeoIP2-Static-IP-Score-Test.mmdb +0 -0
  71. data/test/data/test-data/GeoIP2-User-Count-Test.mmdb +0 -0
  72. data/test/data/test-data/GeoLite2-ASN-Test.mmdb +0 -0
  73. data/test/data/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb +0 -0
  74. data/test/data/test-data/MaxMind-DB-string-value-entries.mmdb +0 -0
  75. data/test/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb +0 -0
  76. data/test/data/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb +0 -0
  77. data/test/data/test-data/MaxMind-DB-test-decoder.mmdb +0 -0
  78. data/test/data/test-data/MaxMind-DB-test-ipv4-24.mmdb +0 -0
  79. data/test/data/test-data/MaxMind-DB-test-ipv4-28.mmdb +0 -0
  80. data/test/data/test-data/MaxMind-DB-test-ipv4-32.mmdb +0 -0
  81. data/test/data/test-data/MaxMind-DB-test-ipv6-24.mmdb +0 -0
  82. data/test/data/test-data/MaxMind-DB-test-ipv6-28.mmdb +0 -0
  83. data/test/data/test-data/MaxMind-DB-test-ipv6-32.mmdb +0 -0
  84. data/test/data/test-data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  85. data/test/data/test-data/MaxMind-DB-test-mixed-24.mmdb +0 -0
  86. data/test/data/test-data/MaxMind-DB-test-mixed-28.mmdb +0 -0
  87. data/test/data/test-data/MaxMind-DB-test-mixed-32.mmdb +0 -0
  88. data/test/data/test-data/MaxMind-DB-test-nested.mmdb +0 -0
  89. data/test/data/test-data/MaxMind-DB-test-pointer-decoder.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 +691 -0
  93. data/test/data/tidyall.ini +5 -0
  94. data/test/test_client.rb +426 -0
  95. data/test/test_model_country.rb +1 -1
  96. data/test/test_model_names.rb +1 -1
  97. data/test/test_reader.rb +92 -1
  98. metadata +194 -10
  99. data/Gemfile.lock +0 -36
@@ -1,7 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module MaxMind::GeoIP2
4
- # An AddressNotFoundError means the IP address was not found in the database.
5
- class AddressNotFoundError < RuntimeError
3
+ module MaxMind
4
+ module GeoIP2
5
+ # An AddressNotFoundError means the IP address was not found in the
6
+ # database or the web service said the IP address was not found.
7
+ class AddressNotFoundError < RuntimeError
8
+ end
9
+
10
+ # An HTTPError means there was an unexpected HTTP status or response.
11
+ class HTTPError < RuntimeError
12
+ end
13
+
14
+ # An AddressInvalidError means the IP address was invalid.
15
+ class AddressInvalidError < RuntimeError
16
+ end
17
+
18
+ # An AddressReservedError means the IP address is reserved.
19
+ class AddressReservedError < RuntimeError
20
+ end
21
+
22
+ # An AuthenticationError means there was a problem authenticating to the
23
+ # web service.
24
+ class AuthenticationError < RuntimeError
25
+ end
26
+
27
+ # An InsufficientFundsError means the account is out of credits.
28
+ class InsufficientFundsError < RuntimeError
29
+ end
30
+
31
+ # A PermissionRequiredError means the account does not have permission to
32
+ # use the requested service.
33
+ class PermissionRequiredError < RuntimeError
34
+ end
35
+
36
+ # An InvalidRequestError means the web service returned an error and there
37
+ # is no more specific error class.
38
+ class InvalidRequestError < RuntimeError
39
+ end
6
40
  end
7
41
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+
5
+ module MaxMind
6
+ module GeoIP2
7
+ module Model
8
+ # @!visibility private
9
+ class Abstract
10
+ def initialize(record)
11
+ @record = record
12
+
13
+ ip = IPAddr.new(record['ip_address']).mask(record['prefix_length'])
14
+ record['network'] = format('%s/%d', ip.to_s, record['prefix_length'])
15
+ end
16
+
17
+ protected
18
+
19
+ def get(key)
20
+ if @record.nil? || !@record.key?(key)
21
+ return false if key.start_with?('is_')
22
+
23
+ return nil
24
+ end
25
+
26
+ @record[key]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind
6
+ module GeoIP2
7
+ module Model
8
+ # Model class for the Anonymous IP database.
9
+ class AnonymousIP < Abstract
10
+ # This is true if the IP address belongs to any sort of anonymous network.
11
+ #
12
+ # @return [Boolean]
13
+ def anonymous?
14
+ get('is_anonymous')
15
+ end
16
+
17
+ # This is true if the IP address is registered to an anonymous VPN
18
+ # provider. If a VPN provider does not register subnets under names
19
+ # associated with them, we will likely only flag their IP ranges using the
20
+ # hosting_provider? method.
21
+ #
22
+ # @return [Boolean]
23
+ def anonymous_vpn?
24
+ get('is_anonymous_vpn')
25
+ end
26
+
27
+ # This is true if the IP address belongs to a hosting or VPN provider (see
28
+ # description of the anonymous_vpn? method).
29
+ #
30
+ # @return [Boolean]
31
+ def hosting_provider?
32
+ get('is_hosting_provider')
33
+ end
34
+
35
+ # The IP address that the data in the model is for.
36
+ #
37
+ # @return [String]
38
+ def ip_address
39
+ get('ip_address')
40
+ end
41
+
42
+ # The network in CIDR notation associated with the record. In particular,
43
+ # this is the largest network where all of the fields besides ip_address
44
+ # have the same value.
45
+ #
46
+ # @return [String]
47
+ def network
48
+ get('network')
49
+ end
50
+
51
+ # This is true if the IP address belongs to a public proxy.
52
+ #
53
+ # @return [Boolean]
54
+ def public_proxy?
55
+ get('is_public_proxy')
56
+ end
57
+
58
+ # This is true if the IP address is on a suspected anonymizing network
59
+ # and belongs to a residential ISP.
60
+ #
61
+ # @return [Boolean]
62
+ def residential_proxy?
63
+ get('is_residential_proxy')
64
+ end
65
+
66
+ # This is true if the IP address is a Tor exit node.
67
+ #
68
+ # @return [Boolean]
69
+ def tor_exit_node?
70
+ get('is_tor_exit_node')
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind
6
+ module GeoIP2
7
+ module Model
8
+ # Model class for the GeoLite2 ASN database.
9
+ class ASN < Abstract
10
+ # The autonomous system number associated with the IP address.
11
+ #
12
+ # @return [Integer, nil]
13
+ def autonomous_system_number
14
+ get('autonomous_system_number')
15
+ end
16
+
17
+ # The organization associated with the registered autonomous system number
18
+ # for the IP address.
19
+ #
20
+ # @return [String, nil]
21
+ def autonomous_system_organization
22
+ get('autonomous_system_organization')
23
+ end
24
+
25
+ # The IP address that the data in the model is for.
26
+ #
27
+ # @return [String]
28
+ def ip_address
29
+ get('ip_address')
30
+ end
31
+
32
+ # The network in CIDR notation associated with the record. In particular,
33
+ # this is the largest network where all of the fields besides ip_address
34
+ # have the same value.
35
+ #
36
+ # @return [String]
37
+ def network
38
+ get('network')
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -6,54 +6,73 @@ require 'maxmind/geoip2/record/location'
6
6
  require 'maxmind/geoip2/record/postal'
7
7
  require 'maxmind/geoip2/record/subdivision'
8
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 Country for inherited methods.
18
- class City < Country
19
- # City data for the IP address. See MaxMind::GeoIP2::Record::City.
20
- attr_reader :city
21
-
22
- # Location data for the IP address. See MaxMind::GeoIP2::Record::Location.
23
- attr_reader :location
24
-
25
- # Postal data for the IP address. See MaxMind::GeoIP2::Record::Postal.
26
- attr_reader :postal
27
-
28
- # An array of MaxMind::GeoIP2::Record::Subdivision objects representing the
29
- # country subdivisions for the IP address. The number and type of
30
- # subdivisions varies by country, but a subdivision is typically a state,
31
- # province, country, etc. Subdivisions are ordered from most general
32
- # (largest) to most specific (smallest). If the response did not contain
33
- # any subdivisions, this attribute will be an empty array.
34
- attr_reader :subdivisions
35
-
36
- def initialize(record, locales) # :nodoc:
37
- super(record, locales)
38
- @city = MaxMind::GeoIP2::Record::City.new(record['city'], locales)
39
- @location = MaxMind::GeoIP2::Record::Location.new(record['location'])
40
- @postal = MaxMind::GeoIP2::Record::Postal.new(record['postal'])
41
- @subdivisions = create_subdivisions(record['subdivisions'], locales)
42
- end
9
+ module MaxMind
10
+ module GeoIP2
11
+ module Model
12
+ # Model class for the data returned by the GeoIP2 City web service and
13
+ # database. It is also used for GeoLite2 City lookups.
14
+ #
15
+ # The only difference between the City and Insights model classes is which
16
+ # fields in each record may be populated. See
17
+ # https://dev.maxmind.com/geoip/geoip2/web-services for more details.
18
+ #
19
+ # See {MaxMind::GeoIP2::Model::Country} for inherited methods.
20
+ class City < Country
21
+ # City data for the IP address.
22
+ #
23
+ # @return [MaxMind::GeoIP2::Record::City]
24
+ attr_reader :city
43
25
 
44
- # Return an object representing the most specific subdivision returned. If
45
- # the response did not contain any subdivisions, this method returns nil.
46
- def most_specific_subdivision
47
- @subdivisions.last
48
- end
26
+ # Location data for the IP address.
27
+ #
28
+ # @return [MaxMind::GeoIP2::Record::Location]
29
+ attr_reader :location
30
+
31
+ # Postal data for the IP address.
32
+ #
33
+ # @return [MaxMind::GeoIP2::Record::Postal]
34
+ attr_reader :postal
35
+
36
+ # The country subdivisions for the IP address.
37
+ #
38
+ # The number and type of subdivisions varies by country, but a subdivision
39
+ # is typically a state, province, country, etc. Subdivisions are ordered
40
+ # from most general (largest) to most specific (smallest).
41
+ #
42
+ # If the response did not contain any subdivisions, this attribute will be
43
+ # an empty array.
44
+ #
45
+ # @return [Array<MaxMind::GeoIP2::Record::Subdivision>]
46
+ attr_reader :subdivisions
47
+
48
+ # @!visibility private
49
+ def initialize(record, locales)
50
+ super(record, locales)
51
+ @city = MaxMind::GeoIP2::Record::City.new(record['city'], locales)
52
+ @location = MaxMind::GeoIP2::Record::Location.new(record['location'])
53
+ @postal = MaxMind::GeoIP2::Record::Postal.new(record['postal'])
54
+ @subdivisions = create_subdivisions(record['subdivisions'], locales)
55
+ end
56
+
57
+ # The most specific subdivision returned.
58
+ #
59
+ # If the response did not contain any subdivisions, this method returns
60
+ # nil.
61
+ #
62
+ # @return [MaxMind::GeoIP2::Record::Subdivision, nil]
63
+ def most_specific_subdivision
64
+ @subdivisions.last
65
+ end
49
66
 
50
- private
67
+ private
51
68
 
52
- def create_subdivisions(subdivisions, locales)
53
- return [] if subdivisions.nil?
69
+ def create_subdivisions(subdivisions, locales)
70
+ return [] if subdivisions.nil?
54
71
 
55
- subdivisions.map do |s|
56
- MaxMind::GeoIP2::Record::Subdivision.new(s, locales)
72
+ subdivisions.map do |s|
73
+ MaxMind::GeoIP2::Record::Subdivision.new(s, locales)
74
+ end
75
+ end
57
76
  end
58
77
  end
59
78
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxmind/geoip2/model/abstract'
4
+
5
+ module MaxMind
6
+ module GeoIP2
7
+ module Model
8
+ # Model class for the GeoIP2 Connection Type database.
9
+ class ConnectionType < Abstract
10
+ # The connection type may take the following values: "Dialup", "Cable/DSL",
11
+ # "Corporate", "Cellular". Additional values may be added in the future.
12
+ #
13
+ # @return [String, nil]
14
+ def connection_type
15
+ get('connection_type')
16
+ end
17
+
18
+ # The IP address that the data in the model is for.
19
+ #
20
+ # @return [String]
21
+ def ip_address
22
+ get('ip_address')
23
+ end
24
+
25
+ # The network in CIDR notation associated with the record. In particular,
26
+ # this is the largest network where all of the fields besides ip_address
27
+ # have the same value.
28
+ #
29
+ # @return [String]
30
+ def network
31
+ get('network')
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,54 +2,73 @@
2
2
 
3
3
  require 'maxmind/geoip2/record/continent'
4
4
  require 'maxmind/geoip2/record/country'
5
+ require 'maxmind/geoip2/record/maxmind'
5
6
  require 'maxmind/geoip2/record/represented_country'
6
7
  require 'maxmind/geoip2/record/traits'
7
8
 
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. See MaxMind::GeoIP2::Record::Continent.
13
- attr_reader :continent
14
-
15
- # Country data for the IP address. This object represents the country where
16
- # MaxMind believes the end user is located. See
17
- # MaxMind::GeoIP2::Record::Country.
18
- attr_reader :country
19
-
20
- # Registered country data for the IP address. This record represents the
21
- # country where the ISP has registered a given IP block and may differ from
22
- # the user's country. See MaxMind::GeoIP2::Record::Country.
23
- attr_reader :registered_country
24
-
25
- # Represented country data for the IP address. The represented country is
26
- # used for things like military bases. It is only present when the
27
- # represented country differs from the country. See
28
- # MaxMind::GeoIP2::Record::RepresentedCountry.
29
- attr_reader :represented_country
30
-
31
- # Data for the traits of the IP address. See
32
- # MaxMind::GeoIP2::Record::Traits.
33
- attr_reader :traits
34
-
35
- def initialize(record, locales) # :nodoc:
36
- @continent = MaxMind::GeoIP2::Record::Continent.new(
37
- record['continent'],
38
- locales,
39
- )
40
- @country = MaxMind::GeoIP2::Record::Country.new(
41
- record['country'],
42
- locales,
43
- )
44
- @registered_country = MaxMind::GeoIP2::Record::Country.new(
45
- record['registered_country'],
46
- locales,
47
- )
48
- @represented_country = MaxMind::GeoIP2::Record::RepresentedCountry.new(
49
- record['represented_country'],
50
- locales,
51
- )
52
- @traits = MaxMind::GeoIP2::Record::Traits.new(record['traits'])
9
+ module MaxMind
10
+ module GeoIP2
11
+ module Model
12
+ # Model class for the data returned by the GeoIP2 Country web service and
13
+ # database. It is also used for GeoLite2 Country lookups.
14
+ class Country
15
+ # Continent data for the IP address.
16
+ #
17
+ # @return [MaxMind::GeoIP2::Record::Continent]
18
+ attr_reader :continent
19
+
20
+ # Country data for the IP address. This object represents the country where
21
+ # MaxMind believes the end user is located.
22
+ #
23
+ # @return [MaxMind::GeoIP2::Record::Country]
24
+ attr_reader :country
25
+
26
+ # Data related to your MaxMind account.
27
+ #
28
+ # @return [MaxMind::GeoIP2::Record::MaxMind]
29
+ attr_reader :maxmind
30
+
31
+ # Registered country data for the IP address. This record represents the
32
+ # country where the ISP has registered a given IP block and may differ from
33
+ # the user's country.
34
+ #
35
+ # @return [MaxMind::GeoIP2::Record::Country]
36
+ attr_reader :registered_country
37
+
38
+ # Represented country data for the IP address. The represented country is
39
+ # used for things like military bases. It is only present when the
40
+ # represented country differs from the country.
41
+ #
42
+ # @return [MaxMind::GeoIP2::Record::RepresentedCountry]
43
+ attr_reader :represented_country
44
+
45
+ # Data for the traits of the IP address.
46
+ #
47
+ # @return [MaxMind::GeoIP2::Record::Traits]
48
+ attr_reader :traits
49
+
50
+ # @!visibility private
51
+ def initialize(record, locales)
52
+ @continent = MaxMind::GeoIP2::Record::Continent.new(
53
+ record['continent'],
54
+ locales,
55
+ )
56
+ @country = MaxMind::GeoIP2::Record::Country.new(
57
+ record['country'],
58
+ locales,
59
+ )
60
+ @maxmind = MaxMind::GeoIP2::Record::MaxMind.new(record['maxmind'])
61
+ @registered_country = MaxMind::GeoIP2::Record::Country.new(
62
+ record['registered_country'],
63
+ locales,
64
+ )
65
+ @represented_country = MaxMind::GeoIP2::Record::RepresentedCountry.new(
66
+ record['represented_country'],
67
+ locales,
68
+ )
69
+ @traits = MaxMind::GeoIP2::Record::Traits.new(record['traits'])
70
+ end
71
+ end
53
72
  end
54
73
  end
55
74
  end