vpndetection 5.6.0 → 5.6.2
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.
- checksums.yaml +4 -4
- data/lib/vpndetection/client.rb +7 -5
- data/lib/vpndetection/database_api.rb +2 -2
- data/lib/vpndetection/errors.rb +5 -4
- data/lib/vpndetection/transport.rb +42 -3
- data/lib/vpndetection/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 12d734b2b201e4ec11c2d0562d1c188bc26417064a2230c120f197c50d81f975
|
|
4
|
+
data.tar.gz: a04054e2f2786070bef386c3abb2e63ca06975cfa6429df62cdb0cfb4f6e91b4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 642c2248cf17028bcaee8b70501bb7acbfde2cdb2141c31b6f2e87702ee8abe450e645677ee62a0e3e8f0239d61752da26dc0c77707bedab39b9d792ccaf85b1
|
|
7
|
+
data.tar.gz: 252d9c789ae4c2c354cbcc52dea4ecf55ce3e3ecc582f085c1a5b5486e26e8e1fc9fe5b439ed049295586a4bce725371bd9a472330eccddad59f255db4404701
|
data/lib/vpndetection/client.rb
CHANGED
|
@@ -340,15 +340,17 @@ module VPNDetection
|
|
|
340
340
|
end
|
|
341
341
|
|
|
342
342
|
# Every address lands in exactly one of `results` and `errors`; an address in
|
|
343
|
-
# neither
|
|
344
|
-
# rather than lost.
|
|
343
|
+
# neither, or with an entry that is not an answer, is the server breaking its
|
|
344
|
+
# own contract, and is reported as that address's error rather than lost.
|
|
345
345
|
def batch_answer(ip, body)
|
|
346
|
-
|
|
346
|
+
served = body['results'][ip]
|
|
347
|
+
failed = body['errors'][ip]
|
|
348
|
+
if Transport.lookup_answer?(served)
|
|
347
349
|
Result.new(served)
|
|
348
|
-
elsif (
|
|
350
|
+
elsif failed.is_a?(Hash)
|
|
349
351
|
Error.from_entry(failed['status'], failed['error'])
|
|
350
352
|
else
|
|
351
|
-
Error.new(:server_error, "the batch answer
|
|
353
|
+
Error.new(:server_error, "the batch answer carried no readable entry for #{ip}", status: 200)
|
|
352
354
|
end
|
|
353
355
|
end
|
|
354
356
|
end
|
|
@@ -181,8 +181,8 @@ module VPNDetection
|
|
|
181
181
|
# every non-2xx as a failure, so it arrives as an ApiError carrying the
|
|
182
182
|
# Location header.
|
|
183
183
|
def redirect_location(id, format, timeout)
|
|
184
|
-
@api.
|
|
185
|
-
raise Error.new(:server_error, 'expected a redirect to object storage')
|
|
184
|
+
_, status, = @api.download_database_with_http_info(id, format, timeout: timeout)
|
|
185
|
+
raise Error.new(:server_error, 'expected a redirect to object storage', status: status)
|
|
186
186
|
rescue ApiError => e
|
|
187
187
|
raise unless e.code == 302
|
|
188
188
|
|
data/lib/vpndetection/errors.rb
CHANGED
|
@@ -97,11 +97,12 @@ module VPNDetection
|
|
|
97
97
|
message.is_a?(String) ? message : nil
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
+
# Seconds as digits, or an HTTP date, and nothing else: `Float()` would also
|
|
101
|
+
# read `0x10`, `1_0` and `1e3` as a wait.
|
|
100
102
|
def self.parse_retry_after(value)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return seconds if seconds && seconds >= 0
|
|
103
|
+
value = value.to_s.strip
|
|
104
|
+
return nil if value.empty?
|
|
105
|
+
return Integer(value, 10) if value.match?(/\A\d+\z/)
|
|
105
106
|
|
|
106
107
|
# The header also permits an HTTP date.
|
|
107
108
|
when_at = Time.httpdate(value) rescue nil
|
|
@@ -80,6 +80,24 @@ module VPNDetection
|
|
|
80
80
|
request
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
# A 2xx the generated client cannot read as the answer it promises is the
|
|
84
|
+
# server's fault, and a retryable :server_error, as it is on the OAuth calls:
|
|
85
|
+
# a proxy's HTML page, a cut-off or empty body, or an object missing a member
|
|
86
|
+
# the spec requires. The generated reader raised a RuntimeError, a
|
|
87
|
+
# JSON::ParserError or an ArgumentError for those, none of them retried, and
|
|
88
|
+
# handed an empty or non-object body back as nil, as if it were the answer.
|
|
89
|
+
def deserialize(response, return_type)
|
|
90
|
+
data = super
|
|
91
|
+
return data unless data.nil?
|
|
92
|
+
|
|
93
|
+
raise Error.new(:server_error, "the API answered with no #{return_type}", status: response.code)
|
|
94
|
+
rescue Error
|
|
95
|
+
raise
|
|
96
|
+
rescue StandardError => e
|
|
97
|
+
raise Error.new(:server_error, "could not read the answer as #{return_type}: #{e.message}",
|
|
98
|
+
status: response.code)
|
|
99
|
+
end
|
|
100
|
+
|
|
83
101
|
# A GET for the presigned link the download endpoint hands out.
|
|
84
102
|
#
|
|
85
103
|
# Built here rather than through {#build_request} so it carries NO
|
|
@@ -162,22 +180,43 @@ module VPNDetection
|
|
|
162
180
|
raise Error.from_transport(response) if transport_failure?(response)
|
|
163
181
|
raise Error.from_status(response.code, response.headers, response.body) unless response.success?
|
|
164
182
|
|
|
165
|
-
|
|
183
|
+
body = parse_object(response)
|
|
184
|
+
begin
|
|
185
|
+
Entitlement.build_from_hash(body)
|
|
186
|
+
rescue StandardError => e
|
|
187
|
+
raise Error.new(:server_error, "could not read the answer as Entitlement: #{e.message}",
|
|
188
|
+
status: response.code)
|
|
189
|
+
end
|
|
166
190
|
end
|
|
167
191
|
|
|
168
192
|
def self.lookup_result(response)
|
|
169
193
|
raise Error.from_transport(response) if transport_failure?(response)
|
|
170
194
|
raise Error.from_status(response.code, response.headers, response.body) unless response.success?
|
|
171
195
|
|
|
172
|
-
|
|
196
|
+
body = parse_object(response)
|
|
197
|
+
return Result.new(body) if lookup_answer?(body)
|
|
198
|
+
|
|
199
|
+
raise Error.new(:server_error, 'the answer carried no ip and is_vpn', status: response.code)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Whether a parsed body is a lookup's answer: every plan's carries `ip` and
|
|
203
|
+
# `is_vpn`, so one without them is a 2xx the call cannot read.
|
|
204
|
+
def self.lookup_answer?(body)
|
|
205
|
+
body.is_a?(Hash) && body['ip'].is_a?(String) && [true, false].include?(body['is_vpn'])
|
|
173
206
|
end
|
|
174
207
|
|
|
175
|
-
# The two maps of a batch answer, each present even when empty.
|
|
208
|
+
# The two maps of a batch answer, each present even when empty. An answer
|
|
209
|
+
# carrying neither is unreadable as a whole, and is retried as one.
|
|
176
210
|
def self.batch_body(response)
|
|
177
211
|
raise Error.from_transport(response) if transport_failure?(response)
|
|
178
212
|
raise Error.from_status(response.code, response.headers, response.body) unless response.success?
|
|
179
213
|
|
|
180
214
|
body = parse_object(response)
|
|
215
|
+
unless body['results'].is_a?(Hash) || body['errors'].is_a?(Hash)
|
|
216
|
+
raise Error.new(:server_error, 'the batch answer carried neither results nor errors',
|
|
217
|
+
status: response.code)
|
|
218
|
+
end
|
|
219
|
+
|
|
181
220
|
{
|
|
182
221
|
'results' => body['results'].is_a?(Hash) ? body['results'] : {},
|
|
183
222
|
'errors' => body['errors'].is_a?(Hash) ? body['errors'] : {},
|
data/lib/vpndetection/version.rb
CHANGED