maxmind-geoip2 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +5 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +32 -0
  5. data/README.md +52 -0
  6. data/lib/maxmind/geoip2.rb +1 -0
  7. data/lib/maxmind/geoip2/client.rb +313 -0
  8. data/lib/maxmind/geoip2/errors.rb +44 -3
  9. data/lib/maxmind/geoip2/model/anonymous_ip.rb +2 -2
  10. data/lib/maxmind/geoip2/model/country.rb +7 -0
  11. data/lib/maxmind/geoip2/model/insights.rb +14 -0
  12. data/lib/maxmind/geoip2/record/maxmind.rb +17 -0
  13. data/maxmind-geoip2.gemspec +2 -1
  14. data/test/test_client.rb +424 -0
  15. metadata +21 -64
  16. data/test/data/LICENSE +0 -4
  17. data/test/data/MaxMind-DB-spec.md +0 -570
  18. data/test/data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  19. data/test/data/README.md +0 -4
  20. data/test/data/bad-data/README.md +0 -7
  21. data/test/data/bad-data/libmaxminddb/libmaxminddb-offset-integer-overflow.mmdb +0 -0
  22. data/test/data/bad-data/maxminddb-golang/cyclic-data-structure.mmdb +0 -0
  23. data/test/data/bad-data/maxminddb-golang/invalid-bytes-length.mmdb +0 -1
  24. data/test/data/bad-data/maxminddb-golang/invalid-data-record-offset.mmdb +0 -0
  25. data/test/data/bad-data/maxminddb-golang/invalid-map-key-length.mmdb +0 -0
  26. data/test/data/bad-data/maxminddb-golang/invalid-string-length.mmdb +0 -1
  27. data/test/data/bad-data/maxminddb-golang/metadata-is-an-uint128.mmdb +0 -1
  28. data/test/data/bad-data/maxminddb-golang/unexpected-bytes.mmdb +0 -0
  29. data/test/data/perltidyrc +0 -12
  30. data/test/data/source-data/GeoIP2-Anonymous-IP-Test.json +0 -48
  31. data/test/data/source-data/GeoIP2-City-Test.json +0 -12852
  32. data/test/data/source-data/GeoIP2-Connection-Type-Test.json +0 -102
  33. data/test/data/source-data/GeoIP2-Country-Test.json +0 -15916
  34. data/test/data/source-data/GeoIP2-DensityIncome-Test.json +0 -14
  35. data/test/data/source-data/GeoIP2-Domain-Test.json +0 -452
  36. data/test/data/source-data/GeoIP2-Enterprise-Test.json +0 -687
  37. data/test/data/source-data/GeoIP2-ISP-Test.json +0 -12593
  38. data/test/data/source-data/GeoIP2-Precision-Enterprise-Test.json +0 -2061
  39. data/test/data/source-data/GeoIP2-Static-IP-Score-Test.json +0 -2132
  40. data/test/data/source-data/GeoIP2-User-Count-Test.json +0 -2837
  41. data/test/data/source-data/GeoLite2-ASN-Test.json +0 -37
  42. data/test/data/source-data/README +0 -15
  43. data/test/data/test-data/GeoIP2-Anonymous-IP-Test.mmdb +0 -0
  44. data/test/data/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb +0 -0
  45. data/test/data/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb +0 -0
  46. data/test/data/test-data/GeoIP2-City-Test.mmdb +0 -0
  47. data/test/data/test-data/GeoIP2-Connection-Type-Test.mmdb +0 -0
  48. data/test/data/test-data/GeoIP2-Country-Test.mmdb +0 -0
  49. data/test/data/test-data/GeoIP2-DensityIncome-Test.mmdb +0 -0
  50. data/test/data/test-data/GeoIP2-Domain-Test.mmdb +0 -0
  51. data/test/data/test-data/GeoIP2-Enterprise-Test.mmdb +0 -0
  52. data/test/data/test-data/GeoIP2-ISP-Test.mmdb +0 -0
  53. data/test/data/test-data/GeoIP2-Precision-Enterprise-Test.mmdb +0 -0
  54. data/test/data/test-data/GeoIP2-Static-IP-Score-Test.mmdb +0 -0
  55. data/test/data/test-data/GeoIP2-User-Count-Test.mmdb +0 -0
  56. data/test/data/test-data/GeoLite2-ASN-Test.mmdb +0 -0
  57. data/test/data/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb +0 -0
  58. data/test/data/test-data/MaxMind-DB-string-value-entries.mmdb +0 -0
  59. data/test/data/test-data/MaxMind-DB-test-broken-pointers-24.mmdb +0 -0
  60. data/test/data/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb +0 -0
  61. data/test/data/test-data/MaxMind-DB-test-decoder.mmdb +0 -0
  62. data/test/data/test-data/MaxMind-DB-test-ipv4-24.mmdb +0 -0
  63. data/test/data/test-data/MaxMind-DB-test-ipv4-28.mmdb +0 -0
  64. data/test/data/test-data/MaxMind-DB-test-ipv4-32.mmdb +0 -0
  65. data/test/data/test-data/MaxMind-DB-test-ipv6-24.mmdb +0 -0
  66. data/test/data/test-data/MaxMind-DB-test-ipv6-28.mmdb +0 -0
  67. data/test/data/test-data/MaxMind-DB-test-ipv6-32.mmdb +0 -0
  68. data/test/data/test-data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  69. data/test/data/test-data/MaxMind-DB-test-mixed-24.mmdb +0 -0
  70. data/test/data/test-data/MaxMind-DB-test-mixed-28.mmdb +0 -0
  71. data/test/data/test-data/MaxMind-DB-test-mixed-32.mmdb +0 -0
  72. data/test/data/test-data/MaxMind-DB-test-nested.mmdb +0 -0
  73. data/test/data/test-data/README.md +0 -26
  74. data/test/data/test-data/maps-with-pointers.raw +0 -0
  75. data/test/data/test-data/write-test-data.pl +0 -641
  76. data/test/data/tidyall.ini +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 59a52bbdfb71c9b0ebe0104616db7425e90f166940aa14a04aef3baa60adce7e
4
- data.tar.gz: 51a5b6921967659ac3ee2a874b7625065b71102ce8fc5ee05b0ea7b94f34f233
2
+ SHA1:
3
+ metadata.gz: 107c7822a5a2de18a3339637547ca8fd8eef5163
4
+ data.tar.gz: 8d730256e5f036178cf13cbd69ed5be2b86afc10
5
5
  SHA512:
6
- metadata.gz: 3a75b0ac6a4da68a4c79b9a8b3a61d45c458279189edb5dc98a5366c4dbac567d6834528c6060ad3dbb759316614649b0d8d9bdf571516ca5d33d639dbf7f76c
7
- data.tar.gz: dfa9fb9b9d1f0a10194ee80b4860cd2b83398fbdc86f042a3e9bcf0c90bd4d7621323524167f19467d46faf94bd790283d5ffdb14d8ba66841615dea4d64c37e
6
+ metadata.gz: 1c9dc8f9b3a115494fa9f20c603f772721568a3759b9e2619fde20751ba71a50109d911effeb7d702d286a2011e56d71049ff6a2b854b177f012bbf6bd904291
7
+ data.tar.gz: a895b54353186ad7fdffec41d9fcf0efa03f093f2dd44a7bbe31e417e13e726a971bb4b88a8a7357c424b16d864061aa563aa150b87160a087d025e852be9a60
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0 (2020-02-26)
4
+
5
+ * Added support for the GeoIP2 Precision web services: Country, City, and
6
+ Insights.
7
+
3
8
  ## 0.1.0 (2020-02-20)
4
9
 
5
10
  * Added support for the Anonymous IP, ASN, Connection Type, Domain, and ISP
data/Gemfile CHANGED
@@ -2,8 +2,10 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
+ gem 'http'
5
6
  gem 'maxmind-db'
6
7
  gem 'minitest', group: :development
7
8
  gem 'rake', group: :development
8
9
  gem 'rubocop', group: :development
9
10
  gem 'rubocop-performance', group: :development
11
+ gem 'webmock', group: :development
@@ -1,13 +1,35 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
+ addressable (2.7.0)
5
+ public_suffix (>= 2.0.2, < 5.0)
4
6
  ast (2.4.0)
7
+ crack (0.4.3)
8
+ safe_yaml (~> 1.0.0)
9
+ domain_name (0.5.20190701)
10
+ unf (>= 0.0.5, < 1.0.0)
11
+ ffi (1.12.2)
12
+ ffi-compiler (1.0.1)
13
+ ffi (>= 1.0.0)
14
+ rake
15
+ hashdiff (1.0.0)
16
+ http (4.3.0)
17
+ addressable (~> 2.3)
18
+ http-cookie (~> 1.0)
19
+ http-form_data (~> 2.2)
20
+ http-parser (~> 1.2.0)
21
+ http-cookie (1.0.3)
22
+ domain_name (~> 0.5)
23
+ http-form_data (2.2.0)
24
+ http-parser (1.2.1)
25
+ ffi-compiler (>= 1.0, < 2.0)
5
26
  jaro_winkler (1.5.4)
6
27
  maxmind-db (1.1.0)
7
28
  minitest (5.14.0)
8
29
  parallel (1.19.1)
9
30
  parser (2.7.0.2)
10
31
  ast (~> 2.4.0)
32
+ public_suffix (4.0.3)
11
33
  rainbow (3.0.0)
12
34
  rake (13.0.1)
13
35
  rexml (3.2.4)
@@ -22,17 +44,27 @@ GEM
22
44
  rubocop-performance (1.5.2)
23
45
  rubocop (>= 0.71.0)
24
46
  ruby-progressbar (1.10.1)
47
+ safe_yaml (1.0.5)
48
+ unf (0.1.4)
49
+ unf_ext
50
+ unf_ext (0.0.7.6)
25
51
  unicode-display_width (1.6.1)
52
+ webmock (3.8.2)
53
+ addressable (>= 2.3.6)
54
+ crack (>= 0.3.2)
55
+ hashdiff (>= 0.4.0, < 2.0.0)
26
56
 
27
57
  PLATFORMS
28
58
  ruby
29
59
 
30
60
  DEPENDENCIES
61
+ http
31
62
  maxmind-db
32
63
  minitest
33
64
  rake
34
65
  rubocop
35
66
  rubocop-performance
67
+ webmock
36
68
 
37
69
  BUNDLED WITH
38
70
  2.1.4
data/README.md CHANGED
@@ -183,6 +183,58 @@ puts record.isp # University of Minnesota
183
183
  puts record.organization # University of Minnesota
184
184
  ```
185
185
 
186
+ ## Web Service Client
187
+
188
+ ### Usage
189
+
190
+ 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.
194
+
195
+ If the request succeeds, the method call will return a model class for the end
196
+ point you called. This model in turn contains multiple record classes, each of
197
+ which represents part of the data returned by the web service.
198
+
199
+ If there is an error, a structured exception is thrown.
200
+
201
+ See the [API documentation](https://www.rubydoc.info/gems/maxmind-geoip2)
202
+ for more details.
203
+
204
+ ### Example
205
+
206
+ ```ruby
207
+ require 'maxmind/geoip2'
208
+
209
+ # This creates a Client object that can be reused across requests.
210
+ # Replace "42" with your account ID and "license_key" with your license
211
+ # key.
212
+ client = MaxMind::GeoIP2::Client.new(
213
+ account_id: 42,
214
+ license_key: 'license_key',
215
+ )
216
+
217
+ # Replace "city" with the method corresponding to the web service that
218
+ # you are using, e.g., "country", "insights".
219
+ record = client.city('128.101.101.101')
220
+
221
+ puts record.country.isoCode # US
222
+ puts record.country.name # United States
223
+ puts record.country.names['zh-CN'] # 美国
224
+
225
+ puts record.most_specific_subdivision.name # Minnesota
226
+ puts record.most_specific_subdivision.iso_code # MN
227
+
228
+ puts record.city.name # Minneapolis
229
+
230
+ puts record.postal.code # 55455
231
+
232
+ puts record.location.latitude # 44.9733
233
+ puts record.location.longitude # -93.2323
234
+
235
+ puts record.traits.network # 128.101.101.101/32
236
+ ```
237
+
186
238
  ## Values to use for Database or Array Keys
187
239
 
188
240
  **We strongly discourage you from using a value from any `names` property
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'maxmind/geoip2/client'
3
4
  require 'maxmind/geoip2/reader'
@@ -0,0 +1,313 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'http'
4
+ require 'json'
5
+ require 'maxmind/geoip2/errors'
6
+ require 'maxmind/geoip2/model/city'
7
+ require 'maxmind/geoip2/model/country'
8
+ require 'maxmind/geoip2/model/insights'
9
+
10
+ module MaxMind::GeoIP2
11
+ # This class provides a client API for all the
12
+ # {https://dev.maxmind.com/geoip/geoip2/web-services/ GeoIP2 Precision web
13
+ # services}. The services are Country, City, and Insights. Each service
14
+ # returns a different set of data about an IP address, with Country returning
15
+ # the least data and Insights the most.
16
+ #
17
+ # Each web service is represented by a different model class, and these model
18
+ # classes in turn contain multiple record classes. The record classes have
19
+ # attributes which contain data about the IP address.
20
+ #
21
+ # If the web service does not return a particular piece of data for an IP
22
+ # address, the associated attribute is not populated.
23
+ #
24
+ # The web service may not return any information for an entire record, in
25
+ # which case all of the attributes for that record class will be empty.
26
+ #
27
+ # == Usage
28
+ #
29
+ # The basic API for this class is the same for all of the web service end
30
+ # points. First you create a web service client object with your MaxMind
31
+ # account ID and license key, then you call the method corresponding to a
32
+ # specific end point, passing it the IP address you want to look up.
33
+ #
34
+ # If the request succeeds, the method call will return a model class for the
35
+ # service you called. This model in turn contains multiple record classes,
36
+ # each of which represents part of the data returned by the web service.
37
+ #
38
+ # If the request fails, the client class throws an exception.
39
+ #
40
+ # == Example
41
+ #
42
+ # require 'maxmind/geoip2'
43
+ #
44
+ # client = MaxMind::GeoIP2::Client.new(
45
+ # account_id: 42,
46
+ # license_key: 'abcdef123456',
47
+ # )
48
+ #
49
+ # # Replace 'city' with the method corresponding to the web service you
50
+ # # are using, e.g., 'country', 'insights'.
51
+ # record = client.city('128.101.101.101')
52
+ #
53
+ # puts record.country.iso_code
54
+ class Client
55
+ # rubocop:disable Metrics/ParameterLists
56
+
57
+ # Create a Client that may be used to query a GeoIP2 Precision web service.
58
+ #
59
+ # Once created, the Client is safe to use for lookups from multiple
60
+ # threads.
61
+ #
62
+ # @param account_id [Integer] your MaxMind account ID.
63
+ #
64
+ # @param license_key [String] your MaxMind license key.
65
+ #
66
+ # @param locales [Array<String>] a list of locale codes to use in the name
67
+ # property from most preferred to least preferred.
68
+ #
69
+ # @param host [String] the host to use when querying the web service.
70
+ #
71
+ # @param timeout [Integer] the number of seconds to wait for a request
72
+ # before timing out. If 0, no timeout is set.
73
+ #
74
+ # @param proxy_address [String] proxy address to use, if any.
75
+ #
76
+ # @param proxy_port [Integer] proxy port to use, if any.
77
+ #
78
+ # @param proxy_username [String] proxy username to use, if any.
79
+ #
80
+ # @param proxy_password [String] proxy password to use, if any.
81
+ def initialize(
82
+ account_id:,
83
+ license_key:,
84
+ locales: ['en'],
85
+ host: 'geoip.maxmind.com',
86
+ timeout: 0,
87
+ proxy_address: '',
88
+ proxy_port: 0,
89
+ proxy_username: '',
90
+ proxy_password: ''
91
+ )
92
+ @account_id = account_id
93
+ @license_key = license_key
94
+ @locales = locales
95
+ @host = host
96
+ @timeout = timeout
97
+ @proxy_address = proxy_address
98
+ @proxy_port = proxy_port
99
+ @proxy_username = proxy_username
100
+ @proxy_password = proxy_password
101
+ end
102
+ # rubocop:enable Metrics/ParameterLists
103
+
104
+ # This method calls the GeoIP2 Precision City web service.
105
+ #
106
+ # @param ip_address [String] IPv4 or IPv6 address as a string. If no
107
+ # address is provided, the address that the web service is called from is
108
+ # used.
109
+ #
110
+ # @raise [HTTP::Error] if there was an error performing the HTTP request,
111
+ # such as an error connecting.
112
+ #
113
+ # @raise [JSON::ParserError] if there was invalid JSON in the response.
114
+ #
115
+ # @raise [HTTPError] if there was a problem with the HTTP response, such as
116
+ # an unexpected HTTP status code.
117
+ #
118
+ # @raise [AddressInvalidError] if the web service believes the IP address
119
+ # to be invalid or missing.
120
+ #
121
+ # @raise [AddressNotFoundError] if the IP address was not found.
122
+ #
123
+ # @raise [AddressReservedError] if the IP address is reserved.
124
+ #
125
+ # @raise [AuthenticationError] if there was a problem authenticating to the
126
+ # web service, such as an invalid or missing license key.
127
+ #
128
+ # @raise [InsufficientFundsError] if your account is out of credit.
129
+ #
130
+ # @raise [PermissionRequiredError] if your account does not have permission
131
+ # to use the web service.
132
+ #
133
+ # @raise [InvalidRequestError] if the web service responded with an error
134
+ # and there is no more specific error to raise.
135
+ #
136
+ # @return [MaxMind::GeoIP2::Model::City]
137
+ def city(ip_address = 'me')
138
+ response_for('city', MaxMind::GeoIP2::Model::City, ip_address)
139
+ end
140
+
141
+ # This method calls the GeoIP2 Precision Country web service.
142
+ #
143
+ # @param ip_address [String] IPv4 or IPv6 address as a string. If no
144
+ # address is provided, the address that the web service is called from is
145
+ # used.
146
+ #
147
+ # @raise [HTTP::Error] if there was an error performing the HTTP request,
148
+ # such as an error connecting.
149
+ #
150
+ # @raise [JSON::ParserError] if there was invalid JSON in the response.
151
+ #
152
+ # @raise [HTTPError] if there was a problem with the HTTP response, such as
153
+ # an unexpected HTTP status code.
154
+ #
155
+ # @raise [AddressInvalidError] if the web service believes the IP address
156
+ # to be invalid or missing.
157
+ #
158
+ # @raise [AddressNotFoundError] if the IP address was not found.
159
+ #
160
+ # @raise [AddressReservedError] if the IP address is reserved.
161
+ #
162
+ # @raise [AuthenticationError] if there was a problem authenticating to the
163
+ # web service, such as an invalid or missing license key.
164
+ #
165
+ # @raise [InsufficientFundsError] if your account is out of credit.
166
+ #
167
+ # @raise [PermissionRequiredError] if your account does not have permission
168
+ # to use the web service.
169
+ #
170
+ # @raise [InvalidRequestError] if the web service responded with an error
171
+ # and there is no more specific error to raise.
172
+ #
173
+ # @return [MaxMind::GeoIP2::Model::Country]
174
+ def country(ip_address = 'me')
175
+ response_for('country', MaxMind::GeoIP2::Model::Country, ip_address)
176
+ end
177
+
178
+ # This method calls the GeoIP2 Precision Insights web service.
179
+ #
180
+ # @param ip_address [String] IPv4 or IPv6 address as a string. If no
181
+ # address is provided, the address that the web service is called from is
182
+ # used.
183
+ #
184
+ # @raise [HTTP::Error] if there was an error performing the HTTP request,
185
+ # such as an error connecting.
186
+ #
187
+ # @raise [JSON::ParserError] if there was invalid JSON in the response.
188
+ #
189
+ # @raise [HTTPError] if there was a problem with the HTTP response, such as
190
+ # an unexpected HTTP status code.
191
+ #
192
+ # @raise [AddressInvalidError] if the web service believes the IP address
193
+ # to be invalid or missing.
194
+ #
195
+ # @raise [AddressNotFoundError] if the IP address was not found.
196
+ #
197
+ # @raise [AddressReservedError] if the IP address is reserved.
198
+ #
199
+ # @raise [AuthenticationError] if there was a problem authenticating to the
200
+ # web service, such as an invalid or missing license key.
201
+ #
202
+ # @raise [InsufficientFundsError] if your account is out of credit.
203
+ #
204
+ # @raise [PermissionRequiredError] if your account does not have permission
205
+ # to use the web service.
206
+ #
207
+ # @raise [InvalidRequestError] if the web service responded with an error
208
+ # and there is no more specific error to raise.
209
+ #
210
+ # @return [MaxMind::GeoIP2::Model::Insights]
211
+ def insights(ip_address = 'me')
212
+ response_for('insights', MaxMind::GeoIP2::Model::Insights, ip_address)
213
+ end
214
+
215
+ private
216
+
217
+ def response_for(endpoint, model_class, ip_address)
218
+ record = get(endpoint, ip_address)
219
+
220
+ model_class.new(record, @locales)
221
+ end
222
+
223
+ # rubocop:disable Metrics/CyclomaticComplexity
224
+ # rubocop:disable Metrics/PerceivedComplexity
225
+ def get(endpoint, ip_address)
226
+ url = 'https://' + @host + '/geoip/v2.1/' + endpoint + '/' + ip_address
227
+
228
+ headers = HTTP.basic_auth(user: @account_id, pass: @license_key)
229
+ .headers(
230
+ accept: 'application/json',
231
+ user_agent: 'MaxMind-GeoIP2-ruby',
232
+ )
233
+ timeout = @timeout > 0 ? headers.timeout(@timeout) : headers
234
+
235
+ proxy = timeout
236
+ if @proxy_address != ''
237
+ opts = {}
238
+ opts[:proxy_port] = @proxy_port if @proxy_port != 0
239
+ opts[:proxy_username] = @proxy_username if @proxy_username != ''
240
+ opts[:proxy_password] = @proxy_password if @proxy_password != ''
241
+ proxy = timeout.via(@proxy_address, opts)
242
+ end
243
+
244
+ response = proxy.get(url)
245
+
246
+ body = response.to_s
247
+ is_json = response.headers[:content_type]&.include?('json')
248
+
249
+ if response.status.client_error?
250
+ return handle_client_error(endpoint, response.code, body, is_json)
251
+ end
252
+
253
+ if response.status.server_error?
254
+ raise HTTPError,
255
+ "Received server error response (#{response.code}) for #{endpoint} with body #{body}"
256
+ end
257
+
258
+ if response.code != 200
259
+ raise HTTPError,
260
+ "Received unexpected response (#{response.code}) for #{endpoint} with body #{body}"
261
+ end
262
+
263
+ handle_success(endpoint, body, is_json)
264
+ end
265
+ # rubocop:enable Metrics/CyclomaticComplexity
266
+ # rubocop:enable Metrics/PerceivedComplexity
267
+
268
+ # rubocop:disable Metrics/CyclomaticComplexity
269
+ def handle_client_error(endpoint, status, body, is_json)
270
+ if !is_json
271
+ raise HTTPError,
272
+ "Received client error response (#{status}) for #{endpoint} but it is not JSON: #{body}"
273
+ end
274
+
275
+ error = JSON.parse(body)
276
+
277
+ if !error.key?('code') || !error.key?('error')
278
+ raise HTTPError,
279
+ "Received client error response (#{status}) that is JSON but does not specify code or error keys: #{body}"
280
+ end
281
+
282
+ case error['code']
283
+ when 'IP_ADDRESS_INVALID', 'IP_ADDRESS_REQUIRED'
284
+ raise AddressInvalidError, error['error']
285
+ when 'IP_ADDRESS_NOT_FOUND'
286
+ raise AddressNotFoundError, error['error']
287
+ when 'IP_ADDRESS_RESERVED'
288
+ raise AddressReservedError, error['error']
289
+ when 'ACCOUNT_ID_REQUIRED',
290
+ 'ACCOUNT_ID_UNKNOWN',
291
+ 'AUTHORIZATION_INVALID',
292
+ 'LICENSE_KEY_REQUIRED'
293
+ raise AuthenticationError, error['error']
294
+ when 'INSUFFICIENT_FUNDS'
295
+ raise InsufficientFundsError, error['error']
296
+ when 'PERMISSION_REQUIRED'
297
+ raise PermissionRequiredError, error['error']
298
+ else
299
+ raise InvalidRequestError, error['error']
300
+ end
301
+ end
302
+ # rubocop:enable Metrics/CyclomaticComplexity
303
+
304
+ def handle_success(endpoint, body, is_json)
305
+ if !is_json
306
+ raise HTTPError,
307
+ "Received a success response for #{endpoint} but it is not JSON: #{body}"
308
+ end
309
+
310
+ JSON.parse(body)
311
+ end
312
+ end
313
+ end