maxmind-geoip2 0.5.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/README.dev.md +1 -1
  4. data/README.md +41 -21
  5. data/lib/maxmind/geoip2/client.rb +27 -18
  6. data/lib/maxmind/geoip2/errors.rb +17 -8
  7. data/lib/maxmind/geoip2/model/city.rb +1 -1
  8. data/lib/maxmind/geoip2/model/enterprise.rb +1 -1
  9. data/lib/maxmind/geoip2/model/insights.rb +1 -1
  10. data/lib/maxmind/geoip2/model/isp.rb +16 -0
  11. data/lib/maxmind/geoip2/reader.rb +44 -20
  12. data/lib/maxmind/geoip2/record/traits.rb +26 -6
  13. data/maxmind-geoip2.gemspec +5 -4
  14. data/test/data/MaxMind-DB-spec.md +15 -11
  15. data/test/data/source-data/GeoIP2-City-Test.json +81 -48
  16. data/test/data/source-data/GeoIP2-Connection-Type-Test.json +20 -0
  17. data/test/data/source-data/GeoIP2-Country-Test.json +46 -58
  18. data/test/data/source-data/GeoIP2-Enterprise-Test.json +61 -3
  19. data/test/data/source-data/GeoIP2-ISP-Test.json +10 -0
  20. data/test/data/source-data/GeoIP2-Precision-Enterprise-Test.json +61 -4
  21. data/test/data/source-data/GeoLite2-ASN-Test.json +4091 -8
  22. data/test/data/source-data/GeoLite2-City-Test.json +12804 -0
  23. data/test/data/source-data/GeoLite2-Country-Test.json +11280 -0
  24. data/test/data/test-data/GeoIP2-Anonymous-IP-Test.mmdb +0 -0
  25. data/test/data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb +0 -0
  26. data/test/data/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb +0 -0
  27. data/test/data/test-data/GeoIP2-City-Test.mmdb +0 -0
  28. data/test/data/test-data/GeoIP2-Connection-Type-Test.mmdb +0 -0
  29. data/test/data/test-data/GeoIP2-Country-Test.mmdb +0 -0
  30. data/test/data/test-data/GeoIP2-DensityIncome-Test.mmdb +0 -0
  31. data/test/data/test-data/GeoIP2-Domain-Test.mmdb +0 -0
  32. data/test/data/test-data/GeoIP2-Enterprise-Test.mmdb +0 -0
  33. data/test/data/test-data/GeoIP2-ISP-Test.mmdb +0 -0
  34. data/test/data/test-data/GeoIP2-Precision-Enterprise-Test.mmdb +0 -0
  35. data/test/data/test-data/GeoIP2-Static-IP-Score-Test.mmdb +0 -0
  36. data/test/data/test-data/GeoIP2-User-Count-Test.mmdb +0 -0
  37. data/test/data/test-data/GeoLite2-ASN-Test.mmdb +0 -0
  38. data/test/data/test-data/GeoLite2-City-Test.mmdb +0 -0
  39. data/test/data/test-data/GeoLite2-Country-Test.mmdb +0 -0
  40. data/test/data/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb +0 -0
  41. data/test/data/test-data/MaxMind-DB-string-value-entries.mmdb +0 -0
  42. data/test/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb +0 -0
  43. data/test/data/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb +0 -0
  44. data/test/data/test-data/MaxMind-DB-test-decoder.mmdb +0 -0
  45. data/test/data/test-data/MaxMind-DB-test-ipv4-24.mmdb +0 -0
  46. data/test/data/test-data/MaxMind-DB-test-ipv4-28.mmdb +0 -0
  47. data/test/data/test-data/MaxMind-DB-test-ipv4-32.mmdb +0 -0
  48. data/test/data/test-data/MaxMind-DB-test-ipv6-24.mmdb +0 -0
  49. data/test/data/test-data/MaxMind-DB-test-ipv6-28.mmdb +0 -0
  50. data/test/data/test-data/MaxMind-DB-test-ipv6-32.mmdb +0 -0
  51. data/test/data/test-data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  52. data/test/data/test-data/MaxMind-DB-test-mixed-24.mmdb +0 -0
  53. data/test/data/test-data/MaxMind-DB-test-mixed-28.mmdb +0 -0
  54. data/test/data/test-data/MaxMind-DB-test-mixed-32.mmdb +0 -0
  55. data/test/data/test-data/MaxMind-DB-test-nested.mmdb +0 -0
  56. data/test/data/test-data/MaxMind-DB-test-pointer-decoder.mmdb +0 -0
  57. data/test/data/test-data/README.md +3 -3
  58. data/test/data/test-data/write-test-data.pl +9 -5
  59. data/test/test_client.rb +2 -2
  60. data/test/test_model_country.rb +16 -0
  61. data/test/test_reader.rb +64 -2
  62. metadata +21 -12
  63. data/test/data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f724b0db8ed7f0700617ba0d37cb08e0b1b10a4ed04d2a59bd8538451d503ffb
4
- data.tar.gz: 172ce815ec47fc1ea64350c9ae5a14880c77a11f429e5a3a7e2bda649903b634
3
+ metadata.gz: 2bdd199c61f9c7116b023d420f1fb0763d05abd7711dd7be0f177113028140ff
4
+ data.tar.gz: 00a081df1adc640dff12ef5fb8670ac9714b9edd1ef3fa65049033a1fa9d385b
5
5
  SHA512:
6
- metadata.gz: ac670d5d555b89fd01fbc638ba32f25cb884c6d138ff60154661bcd75197a2f583f243a5431ae19d137752a4077d4ff160c0132c293428d9764e55c3aeee2b4b
7
- data.tar.gz: add54d450ec8f3d5440fb329bc6cd0299b70eb204fdf8b9d2fdec5338a487efe11f917a5630e5a7b02de498078015746deaa13a835823621c70699d44d5b0321
6
+ metadata.gz: 85a980183be16fa99909d42db32d295ff68a8c718cb31384aef78db8fb287a970d148d12c112fbb9c3cde0a84d396a438a9faf7c196b3e2bfadce93695ebf8e4
7
+ data.tar.gz: 3ef1e40dd82bbf1acf3ddb14b1d774c246c78219463a00b87bfa46c14af7b623ccdfb9af5046c3a1d0b0b8b18fbe4f575d88d28d9930f3b10913c0035326a611
data/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0 (2021-11-18)
4
+
5
+ * Exceptions from this gem now inherit from `MaxMind::GeoIP2::Error`. IP
6
+ address related exceptions now inherit from
7
+ `MaxMind::GeoIP2::AddressError`, which itself inherits from
8
+ `MaxMind::GeoIP2::Error`. Pull Request by gr8bit. GitHub #35.
9
+ * Support for mobile country code (MCC) and mobile network codes (MNC) was
10
+ added for the GeoIP2 ISP and Enterprise databases as well as the GeoIP2
11
+ City and Insights web services. `mobile_country_code` and
12
+ `mobile_network_code` attributes were added to
13
+ `MaxMind::GeoIP2::Model::ISP` for the GeoIP2 ISP database and
14
+ `MaxMind::GeoIP2::Record::Traits` for the Enterprise database and the
15
+ GeoIP2 City and Insights web services. We expect this data to be
16
+ available by late January, 2022.
17
+
18
+ ## 1.0.0 (2021-05-14)
19
+
20
+ * Ruby 2.4 is no longer supported. If you're using Ruby 2.4, please use
21
+ version 0.7.0 of this gem.
22
+ * Expand accepted versions of the `http` gem to include 5.0+.
23
+ * Bump version to 1.0.0 since we have been at 0.x for over a year. There is
24
+ no breaking change.
25
+
26
+ ## 0.7.0 (2021-03-24)
27
+
28
+ * Ensured defaults are set when creating a `MaxMind::GeoIP2::Client` in the
29
+ case when args are explicitly passed in as `nil`. Pull Request by Manoj
30
+ Dayaram. GitHub #31.
31
+
32
+ ## 0.6.0 (2021-03-23)
33
+
34
+ * Updated the `MaxMind::GeoIP2::Reader` constructor to support being called
35
+ using keyword arguments. For example, you may now create a `Reader` using
36
+ `MaxMind::GeoIP2::Reader.new(database: 'GeoIP2-Country.mmdb')` instead of
37
+ using positional arguments. This is intended to make it easier to pass in
38
+ optional arguments. Positional argument calling is still supported.
39
+ * Proxy support was fixed. Pull request by Manoj Dayaram. GitHub #30.
40
+
3
41
  ## 0.5.0 (2020-09-25)
4
42
 
5
43
  * Added the `residential_proxy?` method to
data/README.dev.md CHANGED
@@ -1,4 +1,4 @@
1
1
  # How to release
2
2
 
3
3
  See
4
- [here](https://github.com/maxmind/MaxMind-DB-Reader-ruby/blob/master/README.dev.md).
4
+ [here](https://github.com/maxmind/MaxMind-DB-Reader-ruby/blob/main/README.dev.md).
data/README.md CHANGED
@@ -2,11 +2,9 @@
2
2
 
3
3
  ## Description
4
4
 
5
- This is the Ruby API for the GeoIP2
6
- [webservices](https://dev.maxmind.com/geoip/geoip2/web-services) and
7
- [databases](https://dev.maxmind.com/geoip/geoip2/geolite2/). This API also
8
- works with the free [GeoLite2
9
- databases](https://dev.maxmind.com/geoip/geoip2/geolite2/).
5
+ This is the Ruby API for the GeoIP2 and GeoLite2
6
+ [webservices](https://dev.maxmind.com/geoip/docs/web-services?lang=en)
7
+ and [databases](https://dev.maxmind.com/geoip/docs/databases?lang=en).
10
8
 
11
9
  ## Installation
12
10
 
@@ -47,7 +45,9 @@ for more details.
47
45
  require 'maxmind/geoip2'
48
46
 
49
47
  # This creates the Reader object which should be reused across lookups.
50
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-City.mmdb')
48
+ reader = MaxMind::GeoIP2::Reader.new(
49
+ database: '/usr/share/GeoIP/GeoIP2-City.mmdb',
50
+ )
51
51
 
52
52
  record = reader.city('128.101.101.101')
53
53
 
@@ -74,7 +74,9 @@ puts record.traits.network # 128.101.101.101/32
74
74
  require 'maxmind/geoip2'
75
75
 
76
76
  # This creates the Reader object which should be reused across lookups.
77
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-Country.mmdb')
77
+ reader = MaxMind::GeoIP2::Reader.new(
78
+ database: '/usr/share/GeoIP/GeoIP2-Country.mmdb',
79
+ )
78
80
 
79
81
  record = reader.country('128.101.101.101')
80
82
 
@@ -89,7 +91,9 @@ puts record.country.names['zh-CN'] # '美国'
89
91
  require 'maxmind/geoip2'
90
92
 
91
93
  # This creates the Reader object which should be reused across lookups.
92
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-Enterprise.mmdb')
94
+ reader = MaxMind::GeoIP2::Reader.new(
95
+ database: '/usr/share/GeoIP/GeoIP2-Enterprise.mmdb',
96
+ )
93
97
 
94
98
  record = reader.enterprise('128.101.101.101')
95
99
 
@@ -120,7 +124,9 @@ puts record.traits.network # 128.101.101.101/32
120
124
  require 'maxmind/geoip2'
121
125
 
122
126
  # This creates the Reader object which should be reused across lookups.
123
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-Anonymous-IP.mmdb')
127
+ reader = MaxMind::GeoIP2::Reader.new(
128
+ database: '/usr/share/GeoIP/GeoIP2-Anonymous-IP.mmdb',
129
+ )
124
130
 
125
131
  record = reader.anonymous_ip('128.101.101.101')
126
132
 
@@ -133,7 +139,9 @@ puts "Anonymous" if record.is_anonymous
133
139
  require 'maxmind/geoip2'
134
140
 
135
141
  # This creates the Reader object which should be reused across lookups.
136
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoLite2-ASN.mmdb')
142
+ reader = MaxMind::GeoIP2::Reader.new(
143
+ database: '/usr/share/GeoIP/GeoLite2-ASN.mmdb',
144
+ )
137
145
 
138
146
  record = reader.asn('128.101.101.101')
139
147
 
@@ -147,7 +155,9 @@ puts record.autonomous_system_organization # Example Ltd
147
155
  require 'maxmind/geoip2'
148
156
 
149
157
  # This creates the Reader object which should be reused across lookups.
150
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-Connection-Type.mmdb')
158
+ reader = MaxMind::GeoIP2::Reader.new(
159
+ database: '/usr/share/GeoIP/GeoIP2-Connection-Type.mmdb',
160
+ )
151
161
 
152
162
  record = reader.connection_type('128.101.101.101')
153
163
 
@@ -160,7 +170,9 @@ puts record.connection_type # Cable/DSL
160
170
  require 'maxmind/geoip2'
161
171
 
162
172
  # This creates the Reader object which should be reused across lookups.
163
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-Domain.mmdb')
173
+ reader = MaxMind::GeoIP2::Reader.new(
174
+ database: '/usr/share/GeoIP/GeoIP2-Domain.mmdb',
175
+ )
164
176
 
165
177
  record = reader.domain('128.101.101.101')
166
178
 
@@ -173,7 +185,9 @@ puts record.domain # example.com
173
185
  require 'maxmind/geoip2'
174
186
 
175
187
  # This creates the Reader object which should be reused across lookups.
176
- reader = MaxMind::GeoIP2::Reader.new('/usr/share/GeoIP/GeoIP2-ISP.mmdb')
188
+ reader = MaxMind::GeoIP2::Reader.new(
189
+ database: '/usr/share/GeoIP/GeoIP2-ISP.mmdb',
190
+ )
177
191
 
178
192
  record = reader.isp('128.101.101.101')
179
193
 
@@ -188,9 +202,10 @@ puts record.organization # University of Minnesota
188
202
  ### Usage
189
203
 
190
204
  To use this API, you must create a new `MaxMind::GeoIP2::Client` object
191
- with your account ID and license key, then you call the method
192
- corresponding to a specific end point, passing it the IP address you want
193
- to look up.
205
+ with your account ID and license key. To use the GeoLite2 web service, you
206
+ may also set the `host` parameter to `geolite.info`. You may then you call
207
+ the method corresponding to a specific end point, passing it the IP address
208
+ you want to look up.
194
209
 
195
210
  If the request succeeds, the method call will return a model class for the end
196
211
  point you called. This model in turn contains multiple record classes, each of
@@ -212,13 +227,18 @@ require 'maxmind/geoip2'
212
227
  client = MaxMind::GeoIP2::Client.new(
213
228
  account_id: 42,
214
229
  license_key: 'license_key',
230
+
231
+ # To use the GeoLite2 web service instead of GeoIP2 Precision, set
232
+ # the host parameter to "geolite.info":
233
+ # host: 'geolite.info',
215
234
  )
216
235
 
217
236
  # Replace "city" with the method corresponding to the web service that
218
- # you are using, e.g., "country", "insights".
237
+ # you are using, e.g., "country", "insights". Please note that Insights
238
+ # is only supported by GeoIP2 Precision and not the GeoLite2 web service.
219
239
  record = client.city('128.101.101.101')
220
240
 
221
- puts record.country.isoCode # US
241
+ puts record.country.iso_code # US
222
242
  puts record.country.name # United States
223
243
  puts record.country.names['zh-CN'] # 美国
224
244
 
@@ -260,7 +280,7 @@ point may offer a particular piece of data, MaxMind does not always have
260
280
  every piece of data for any given IP address.
261
281
 
262
282
  See the [GeoIP2 Precision web service
263
- docs](https://dev.maxmind.com/geoip/geoip2/web-services) for details on
283
+ docs](https://dev.maxmind.com/geoip/docs/web-services?lang=en) for details on
264
284
  what data each end point may return.
265
285
 
266
286
  The only piece of data which is always returned is the `ip_address`
@@ -307,7 +327,7 @@ client API, please see [our support page](https://www.maxmind.com/en/support).
307
327
 
308
328
  ## Requirements
309
329
 
310
- This code requires Ruby version 2.4 or higher.
330
+ This code requires Ruby version 2.5 or higher.
311
331
 
312
332
  ## Contributing
313
333
 
@@ -320,7 +340,7 @@ This library uses [Semantic Versioning](https://semver.org/).
320
340
 
321
341
  ## Copyright and License
322
342
 
323
- This software is Copyright (c) 2020 by MaxMind, Inc.
343
+ This software is Copyright (c) 2020-2021 by MaxMind, Inc.
324
344
 
325
345
  This is free software, licensed under the [Apache License, Version
326
346
  2.0](LICENSE-APACHE) or the [MIT License](LICENSE-MIT), at your option.
@@ -11,7 +11,7 @@ require 'maxmind/geoip2/model/insights'
11
11
  module MaxMind
12
12
  module GeoIP2
13
13
  # This class provides a client API for all the
14
- # {https://dev.maxmind.com/geoip/geoip2/web-services/ GeoIP2 Precision web
14
+ # {https://dev.maxmind.com/geoip/docs/web-services?lang=en GeoIP2 Precision web
15
15
  # services}. The services are Country, City, and Insights. Each service
16
16
  # returns a different set of data about an IP address, with Country returning
17
17
  # the least data and Insights the most.
@@ -55,6 +55,8 @@ module MaxMind
55
55
  # puts record.country.iso_code
56
56
  class Client
57
57
  # rubocop:disable Metrics/ParameterLists
58
+ # rubocop:disable Metrics/CyclomaticComplexity
59
+ # rubocop:disable Metrics/PerceivedComplexity
58
60
 
59
61
  # Create a Client that may be used to query a GeoIP2 Precision web service.
60
62
  #
@@ -68,7 +70,9 @@ module MaxMind
68
70
  # @param locales [Array<String>] a list of locale codes to use in the name
69
71
  # property from most preferred to least preferred.
70
72
  #
71
- # @param host [String] the host to use when querying the web service.
73
+ # @param host [String] the host to use when querying the web service. Set
74
+ # this to "geolite.info" to use the GeoLite2 web service instead of
75
+ # GeoIP2 Precision.
72
76
  #
73
77
  # @param timeout [Integer] the number of seconds to wait for a request
74
78
  # before timing out. If 0, no timeout is set.
@@ -96,22 +100,24 @@ module MaxMind
96
100
  )
97
101
  @account_id = account_id
98
102
  @license_key = license_key
99
- @locales = locales
100
- @host = host
101
- @timeout = timeout
102
- @proxy_address = proxy_address
103
- @proxy_port = proxy_port
104
- @proxy_username = proxy_username
105
- @proxy_password = proxy_password
106
- @pool_size = pool_size
103
+ @locales = locales || ['en']
104
+ @host = host || 'geoip.maxmind.com'
105
+ @timeout = timeout || 0
106
+ @proxy_address = proxy_address || ''
107
+ @proxy_port = proxy_port || 0
108
+ @proxy_username = proxy_username || ''
109
+ @proxy_password = proxy_password || ''
110
+ @pool_size = pool_size || 5
107
111
 
108
112
  @connection_pool = ConnectionPool.new(size: @pool_size) do
109
113
  make_http_client.persistent("https://#{@host}")
110
114
  end
111
115
  end
116
+ # rubocop:enable Metrics/PerceivedComplexity
117
+ # rubocop:enable Metrics/CyclomaticComplexity
112
118
  # rubocop:enable Metrics/ParameterLists
113
119
 
114
- # This method calls the GeoIP2 Precision City web service.
120
+ # This method calls the City web service.
115
121
  #
116
122
  # @param ip_address [String] IPv4 or IPv6 address as a string. If no
117
123
  # address is provided, the address that the web service is called from is
@@ -148,7 +154,7 @@ module MaxMind
148
154
  response_for('city', MaxMind::GeoIP2::Model::City, ip_address)
149
155
  end
150
156
 
151
- # This method calls the GeoIP2 Precision Country web service.
157
+ # This method calls the Country web service.
152
158
  #
153
159
  # @param ip_address [String] IPv4 or IPv6 address as a string. If no
154
160
  # address is provided, the address that the web service is called from is
@@ -185,7 +191,10 @@ module MaxMind
185
191
  response_for('country', MaxMind::GeoIP2::Model::Country, ip_address)
186
192
  end
187
193
 
188
- # This method calls the GeoIP2 Precision Insights web service.
194
+ # This method calls the Insights web service.
195
+ #
196
+ # Insights is only supported by the GeoIP2 Precision web service. The
197
+ # GeoLite2 web service does not support it.
189
198
  #
190
199
  # @param ip_address [String] IPv4 or IPv6 address as a string. If no
191
200
  # address is provided, the address that the web service is called from is
@@ -240,11 +249,11 @@ module MaxMind
240
249
 
241
250
  proxy = timeout
242
251
  if @proxy_address != ''
243
- opts = {}
244
- opts[:proxy_port] = @proxy_port if @proxy_port != 0
245
- opts[:proxy_username] = @proxy_username if @proxy_username != ''
246
- opts[:proxy_password] = @proxy_password if @proxy_password != ''
247
- proxy = timeout.via(@proxy_address, opts)
252
+ proxy_params = [@proxy_address]
253
+ proxy_params << (@proxy_port == 0 ? nil : @proxy_port)
254
+ proxy_params << (@proxy_username == '' ? nil : @proxy_username)
255
+ proxy_params << (@proxy_password == '' ? nil : @proxy_password)
256
+ proxy = timeout.via(*proxy_params)
248
257
  end
249
258
 
250
259
  proxy
@@ -2,40 +2,49 @@
2
2
 
3
3
  module MaxMind
4
4
  module GeoIP2
5
+ # Module's base error class
6
+ class Error < StandardError
7
+ end
8
+
9
+ # Base error class for all errors that originate from the IP address
10
+ # itself and will not change when retried.
11
+ class AddressError < Error
12
+ end
13
+
5
14
  # An AddressNotFoundError means the IP address was not found in the
6
15
  # database or the web service said the IP address was not found.
7
- class AddressNotFoundError < RuntimeError
16
+ class AddressNotFoundError < AddressError
8
17
  end
9
18
 
10
19
  # An HTTPError means there was an unexpected HTTP status or response.
11
- class HTTPError < RuntimeError
20
+ class HTTPError < Error
12
21
  end
13
22
 
14
23
  # An AddressInvalidError means the IP address was invalid.
15
- class AddressInvalidError < RuntimeError
24
+ class AddressInvalidError < AddressError
16
25
  end
17
26
 
18
27
  # An AddressReservedError means the IP address is reserved.
19
- class AddressReservedError < RuntimeError
28
+ class AddressReservedError < AddressError
20
29
  end
21
30
 
22
31
  # An AuthenticationError means there was a problem authenticating to the
23
32
  # web service.
24
- class AuthenticationError < RuntimeError
33
+ class AuthenticationError < Error
25
34
  end
26
35
 
27
36
  # An InsufficientFundsError means the account is out of credits.
28
- class InsufficientFundsError < RuntimeError
37
+ class InsufficientFundsError < Error
29
38
  end
30
39
 
31
40
  # A PermissionRequiredError means the account does not have permission to
32
41
  # use the requested service.
33
- class PermissionRequiredError < RuntimeError
42
+ class PermissionRequiredError < Error
34
43
  end
35
44
 
36
45
  # An InvalidRequestError means the web service returned an error and there
37
46
  # is no more specific error class.
38
- class InvalidRequestError < RuntimeError
47
+ class InvalidRequestError < Error
39
48
  end
40
49
  end
41
50
  end
@@ -14,7 +14,7 @@ module MaxMind
14
14
  #
15
15
  # The only difference between the City and Insights model classes is which
16
16
  # fields in each record may be populated. See
17
- # https://dev.maxmind.com/geoip/geoip2/web-services for more details.
17
+ # https://dev.maxmind.com/geoip/docs/web-services?lang=en for more details.
18
18
  #
19
19
  # See {MaxMind::GeoIP2::Model::Country} for inherited methods.
20
20
  class City < Country
@@ -9,7 +9,7 @@ module MaxMind
9
9
  #
10
10
  # The only difference between the City and Insights model classes is which
11
11
  # fields in each record may be populated. See
12
- # https://dev.maxmind.com/geoip/geoip2/web-services for more details.
12
+ # https://dev.maxmind.com/geoip/docs/web-services?lang=en for more details.
13
13
  #
14
14
  # See {MaxMind::GeoIP2::Model::City} for inherited methods.
15
15
  class Enterprise < City
@@ -10,7 +10,7 @@ module MaxMind
10
10
  #
11
11
  # The only difference between the City and Insights model classes is which
12
12
  # fields in each record may be populated. See
13
- # https://dev.maxmind.com/geoip/geoip2/web-services for more details.
13
+ # https://dev.maxmind.com/geoip/docs/web-services?lang=en for more details.
14
14
  class Insights < City
15
15
  end
16
16
  end
@@ -36,6 +36,22 @@ module MaxMind
36
36
  get('isp')
37
37
  end
38
38
 
39
+ # The {https://en.wikipedia.org/wiki/Mobile_country_code mobile country
40
+ # code (MCC)} associated with the IP address and ISP.
41
+ #
42
+ # @return [String, nil]
43
+ def mobile_country_code
44
+ get('mobile_country_code')
45
+ end
46
+
47
+ # The {https://en.wikipedia.org/wiki/Mobile_country_code mobile network
48
+ # code (MNC)} associated with the IP address and ISP.
49
+ #
50
+ # @return [String, nil]
51
+ def mobile_network_code
52
+ get('mobile_network_code')
53
+ end
54
+
39
55
  # The network in CIDR notation associated with the record. In particular,
40
56
  # this is the largest network where all of the fields besides ip_address
41
57
  # have the same value.
@@ -20,13 +20,16 @@ module MaxMind
20
20
  #
21
21
  # require 'maxmind/geoip2'
22
22
  #
23
- # reader = MaxMind::GeoIP2::Reader.new('GeoIP2-Country.mmdb')
23
+ # reader = MaxMind::GeoIP2::Reader.new(database: 'GeoIP2-Country.mmdb')
24
24
  #
25
25
  # record = reader.country('1.2.3.4')
26
26
  # puts record.country.iso_code
27
27
  #
28
28
  # reader.close
29
29
  class Reader
30
+ # rubocop:disable Metrics/CyclomaticComplexity
31
+ # rubocop:disable Metrics/PerceivedComplexity
32
+
30
33
  # Create a Reader for looking up IP addresses in a GeoIP2/GeoLite2 database
31
34
  # file.
32
35
  #
@@ -34,33 +37,54 @@ module MaxMind
34
37
  # Reader and reuse it.
35
38
  #
36
39
  # Once created, the Reader is safe to use for lookups from multiple
37
- # threads. It is safe to use after forking only if you use
38
- # MaxMind::DB::MODE_MEMORY or if your version of Ruby supports IO#pread.
39
- #
40
- # @param database [String] a path to a GeoIP2/GeoLite2 database file.
41
- #
42
- # @param locales [Array<String>] a list of locale codes to use in the name
43
- # property from most preferred to least preferred.
40
+ # threads. It is safe to use after forking.
44
41
  #
45
- # @param options [Hash<Symbol, Symbol>] options controlling the behavior of
46
- # the Reader.
42
+ # @overload initialize(database:, locales: ['en'], mode: MaxMind::DB::MODE_AUTO)
43
+ # @param database [String] a path to a GeoIP2/GeoLite2 database file.
44
+ # @param locales [Array<String>] a list of locale codes to use in the name
45
+ # property from most preferred to least preferred.
46
+ # @param mode [Symbol] Defines how to open the database. It may be one of
47
+ # MaxMind::DB::MODE_AUTO, MaxMind::DB::MODE_FILE, or
48
+ # MaxMind::DB::MODE_MEMORY. If you don't provide one, the Reader uses
49
+ # MaxMind::DB::MODE_AUTO. Refer to the definition of those constants in
50
+ # MaxMind::DB for an explanation of their meaning.
47
51
  #
48
- # @option options [Symbol] :mode Defines how to open the database. It may
49
- # be one of MaxMind::DB::MODE_AUTO, MaxMind::DB::MODE_FILE, or
50
- # MaxMind::DB::MODE_MEMORY. If you don't provide one, the Reader uses
51
- # MaxMind::DB::MODE_AUTO. Refer to the definition of those constants in
52
- # MaxMind::DB for an explanation of their meaning.
53
- #
54
- # @raise [MaxMind::DB::InvalidDatabaseError] if the database is corrupt or
55
- # invalid.
52
+ # @raise [MaxMind::DB::InvalidDatabaseError] if the database is corrupt
53
+ # or invalid.
56
54
  #
57
55
  # @raise [ArgumentError] if the mode is invalid.
58
- def initialize(database, locales = ['en'], options = {})
56
+ def initialize(*args)
57
+ # This if statement is to let us support calling as though we are using
58
+ # Ruby 2.0 keyword arguments. We can't use keyword argument syntax as
59
+ # we want to be backwards compatible with the old way we accepted
60
+ # parameters, which looked like:
61
+ # def initialize(database, locales = ['en'], options = {})
62
+ if args.length == 1 && args[0].instance_of?(Hash)
63
+ database = args[0][:database]
64
+ locales = args[0][:locales]
65
+ mode = args[0][:mode]
66
+ else
67
+ database = args[0]
68
+ locales = args[1]
69
+ mode = args[2].instance_of?(Hash) ? args[2][:mode] : nil
70
+ end
71
+
72
+ if !database.instance_of?(String)
73
+ raise ArgumentError, 'Invalid database parameter'
74
+ end
75
+
76
+ locales = ['en'] if locales.nil? || locales.empty?
77
+
78
+ options = {}
79
+ options[:mode] = mode if !mode.nil?
59
80
  @reader = MaxMind::DB.new(database, options)
81
+
60
82
  @type = @reader.metadata.database_type
61
- locales = ['en'] if locales.empty?
83
+
62
84
  @locales = locales
63
85
  end
86
+ # rubocop:enable Metrics/CyclomaticComplexity
87
+ # rubocop:enable Metrics/PerceivedComplexity
64
88
 
65
89
  # Look up the IP address in the database.
66
90
  #
@@ -13,12 +13,10 @@ module MaxMind
13
13
  # @!visibility private
14
14
  def initialize(record)
15
15
  super(record)
16
- if !record.key?('network') && record.key?('ip_address') &&
16
+ if record && !record.key?('network') && record.key?('ip_address') &&
17
17
  record.key?('prefix_length')
18
18
  ip = IPAddr.new(record['ip_address']).mask(record['prefix_length'])
19
- # We could use ip.prefix instead of record['prefix_length'], but that
20
- # method only becomes available in Ruby 2.5+.
21
- record['network'] = format('%s/%d', ip.to_s, record['prefix_length'])
19
+ record['network'] = format('%s/%d', ip.to_s, ip.prefix)
22
20
  end
23
21
  end
24
22
 
@@ -69,7 +67,7 @@ module MaxMind
69
67
  # NAT, this may differ from the IP address locally assigned to it. This
70
68
  # attribute is returned by all end points.
71
69
  #
72
- # @return [String]
70
+ # @return [String, nil]
73
71
  def ip_address
74
72
  get('ip_address')
75
73
  end
@@ -111,6 +109,28 @@ module MaxMind
111
109
  get('is_legitimate_proxy')
112
110
  end
113
111
 
112
+ # The {https://en.wikipedia.org/wiki/Mobile_country_code mobile country
113
+ # code (MCC)} associated with the IP address and ISP.
114
+ #
115
+ # This attribute is only available from the City and Insights web service
116
+ # and the GeoIP2 Enterprise database.
117
+ #
118
+ # @return [String, nil]
119
+ def mobile_country_code
120
+ get('mobile_country_code')
121
+ end
122
+
123
+ # The {https://en.wikipedia.org/wiki/Mobile_country_code mobile network
124
+ # code (MNC)} associated with the IP address and ISP.
125
+ #
126
+ # This attribute is only available from the City and Insights web service
127
+ # and the GeoIP2 Enterprise database.
128
+ #
129
+ # @return [String, nil]
130
+ def mobile_network_code
131
+ get('mobile_network_code')
132
+ end
133
+
114
134
  # This is true if the IP address belongs to a public proxy. This property
115
135
  # is only available from GeoIP2 Precision Insights.
116
136
  #
@@ -149,7 +169,7 @@ module MaxMind
149
169
  # this is the largest network where all of the fields besides ip_address
150
170
  # have the same value.
151
171
  #
152
- # @return [String]
172
+ # @return [String, nil]
153
173
  def network
154
174
  get('network')
155
175
  end
@@ -5,7 +5,7 @@ Gem::Specification.new do |s|
5
5
  s.files = Dir['**/*']
6
6
  s.name = 'maxmind-geoip2'
7
7
  s.summary = 'A gem for interacting with the GeoIP2 webservices and databases.'
8
- s.version = '0.5.0'
8
+ s.version = '1.1.0'
9
9
 
10
10
  s.description = 'A gem for interacting with the GeoIP2 webservices and databases. MaxMind provides geolocation data as downloadable databases as well as through a webservice.'
11
11
  s.email = 'support@maxmind.com'
@@ -13,15 +13,16 @@ Gem::Specification.new do |s|
13
13
  s.licenses = ['Apache-2.0', 'MIT']
14
14
  s.metadata = {
15
15
  'bug_tracker_uri' => 'https://github.com/maxmind/GeoIP2-ruby/issues',
16
- 'changelog_uri' => 'https://github.com/maxmind/GeoIP2-ruby/blob/master/CHANGELOG.md',
16
+ 'changelog_uri' => 'https://github.com/maxmind/GeoIP2-ruby/blob/main/CHANGELOG.md',
17
17
  'documentation_uri' => 'https://www.rubydoc.info/gems/maxmind-geoip2',
18
18
  'homepage_uri' => 'https://github.com/maxmind/GeoIP2-ruby',
19
+ 'rubygems_mfa_required' => 'true',
19
20
  'source_code_uri' => 'https://github.com/maxmind/GeoIP2-ruby',
20
21
  }
21
- s.required_ruby_version = '>= 2.4.0'
22
+ s.required_ruby_version = '>= 2.5.0'
22
23
 
23
24
  s.add_runtime_dependency 'connection_pool', ['~> 2.2']
24
- s.add_runtime_dependency 'http', ['~> 4.3']
25
+ s.add_runtime_dependency 'http', '>= 4.3', '< 6.0'
25
26
  s.add_runtime_dependency 'maxmind-db', ['~> 1.1']
26
27
 
27
28
  s.add_development_dependency 'minitest'