pingpp 2.0.8 → 2.0.11
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/data/ca-certificates.crt +5 -5075
- data/lib/pingpp/version.rb +1 -1
- data/lib/pingpp.rb +34 -38
- metadata +2 -3
- data/lib/pingpp/certificate_blacklist.rb +0 -51
data/lib/pingpp/version.rb
CHANGED
data/lib/pingpp.rb
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
require 'cgi'
|
4
4
|
require 'set'
|
5
5
|
require 'openssl'
|
6
|
-
require '
|
6
|
+
require 'rest-client'
|
7
7
|
require 'json'
|
8
|
+
require 'base64'
|
8
9
|
|
9
10
|
# Version
|
10
11
|
require 'pingpp/version'
|
@@ -21,7 +22,6 @@ require 'pingpp/pingpp_object'
|
|
21
22
|
require 'pingpp/api_resource'
|
22
23
|
require 'pingpp/singleton_api_resource'
|
23
24
|
require 'pingpp/list_object'
|
24
|
-
require 'pingpp/certificate_blacklist'
|
25
25
|
require 'pingpp/charge'
|
26
26
|
require 'pingpp/refund'
|
27
27
|
require 'pingpp/red_envelope'
|
@@ -43,16 +43,15 @@ module Pingpp
|
|
43
43
|
DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/data/ca-certificates.crt'
|
44
44
|
@api_base = 'https://api.pingxx.com'
|
45
45
|
|
46
|
-
@api_version = '2015-
|
46
|
+
@api_version = '2015-10-10'
|
47
47
|
|
48
48
|
@ssl_bundle_path = DEFAULT_CA_BUNDLE_PATH
|
49
49
|
@verify_ssl_certs = true
|
50
|
-
@CERTIFICATE_VERIFIED = false
|
51
50
|
|
52
51
|
HEADERS_TO_PARSE = [:pingpp_one_version, :pingpp_sdk_version]
|
53
52
|
|
54
53
|
class << self
|
55
|
-
attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version, :parsed_headers
|
54
|
+
attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version, :parsed_headers, :private_key_path
|
56
55
|
end
|
57
56
|
|
58
57
|
def self.api_url(url='')
|
@@ -92,15 +91,19 @@ module Pingpp
|
|
92
91
|
'email support@pingxx.com if you have any questions.)')
|
93
92
|
end
|
94
93
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
94
|
+
if verify_ssl_certs
|
95
|
+
request_opts = {:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
|
96
|
+
:ssl_ca_file => @ssl_bundle_path,
|
97
|
+
:ssl_version => 'TLSv1'}
|
98
|
+
else
|
99
|
+
request_opts = {:verify_ssl => false,
|
100
|
+
:ssl_version => 'TLSv1'}
|
101
|
+
unless @verify_ssl_warned
|
102
|
+
@verify_ssl_warned = true
|
103
|
+
$stderr.puts("WARNING: Running without SSL cert verification. " \
|
104
|
+
"You should never do this in production. " \
|
105
|
+
"Execute 'Pingpp.verify_ssl_certs = true' to enable verification.")
|
106
|
+
end
|
104
107
|
end
|
105
108
|
|
106
109
|
params = Util.objects_to_ids(params)
|
@@ -115,7 +118,7 @@ module Pingpp
|
|
115
118
|
payload = JSON.generate(params)
|
116
119
|
end
|
117
120
|
|
118
|
-
request_opts.update(:headers => request_headers(api_key, method.to_s.downcase.to_sym == :post).update(headers),
|
121
|
+
request_opts.update(:headers => request_headers(api_key, method.to_s.downcase.to_sym == :post, payload).update(headers),
|
119
122
|
:method => method, :open_timeout => 30,
|
120
123
|
:payload => payload, :url => url, :timeout => 80)
|
121
124
|
|
@@ -146,23 +149,6 @@ module Pingpp
|
|
146
149
|
|
147
150
|
private
|
148
151
|
|
149
|
-
def self.ssl_preflight_passed?
|
150
|
-
if !verify_ssl_certs && !@no_verify
|
151
|
-
$stderr.puts "WARNING: Running without SSL cert verification. " +
|
152
|
-
"Execute 'Pingpp.verify_ssl_certs = true' to enable verification."
|
153
|
-
|
154
|
-
@no_verify = true
|
155
|
-
|
156
|
-
elsif !Util.file_readable(@ssl_bundle_path) && !@no_bundle
|
157
|
-
$stderr.puts "WARNING: Running without SSL cert verification " +
|
158
|
-
"because #{@ssl_bundle_path} isn't readable"
|
159
|
-
|
160
|
-
@no_bundle = true
|
161
|
-
end
|
162
|
-
|
163
|
-
!(@no_verify || @no_bundle)
|
164
|
-
end
|
165
|
-
|
166
152
|
def self.user_agent
|
167
153
|
@uname ||= get_uname
|
168
154
|
lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
|
@@ -189,7 +175,7 @@ module Pingpp
|
|
189
175
|
map { |k,v| "#{k}=#{Util.url_encode(v)}" }.join('&')
|
190
176
|
end
|
191
177
|
|
192
|
-
def self.request_headers(api_key, is_post=false)
|
178
|
+
def self.request_headers(api_key, is_post=false, data=nil)
|
193
179
|
headers = {
|
194
180
|
:user_agent => "Pingpp/v1 RubyBindings/#{Pingpp::VERSION}",
|
195
181
|
:authorization => "Bearer #{api_key}",
|
@@ -205,6 +191,13 @@ module Pingpp
|
|
205
191
|
headers.update(:x_pingpp_client_raw_user_agent => user_agent.inspect,
|
206
192
|
:error => "#{e} (#{e.class})")
|
207
193
|
end
|
194
|
+
|
195
|
+
if is_post && private_key_path && data
|
196
|
+
signature = sign_request(data, private_key_path)
|
197
|
+
headers.update(:pingplusplus_signature => signature)
|
198
|
+
end
|
199
|
+
|
200
|
+
headers
|
208
201
|
end
|
209
202
|
|
210
203
|
def self.execute_request(opts)
|
@@ -223,6 +216,11 @@ module Pingpp
|
|
223
216
|
Util.symbolize_names(response)
|
224
217
|
end
|
225
218
|
|
219
|
+
def self.sign_request(data, key_path)
|
220
|
+
pkey = OpenSSL::PKey.read(File.read(key_path))
|
221
|
+
return Base64.strict_encode64(pkey.sign(OpenSSL::Digest::SHA256.new, data))
|
222
|
+
end
|
223
|
+
|
226
224
|
def self.general_api_error(rcode, rbody)
|
227
225
|
APIError.new("Invalid response object from API: #{rbody.inspect} " +
|
228
226
|
"(HTTP response code was #{rcode})", rcode, rbody)
|
@@ -271,7 +269,7 @@ module Pingpp
|
|
271
269
|
def self.handle_restclient_error(e)
|
272
270
|
connection_message = "Please check your internet connection and try again. " \
|
273
271
|
"If this problem persists, you should check Pingpp's service status at " \
|
274
|
-
"https://
|
272
|
+
"https://www.pingxx.com/status"
|
275
273
|
|
276
274
|
case e
|
277
275
|
when RestClient::RequestTimeout
|
@@ -284,8 +282,7 @@ module Pingpp
|
|
284
282
|
when RestClient::SSLCertificateNotVerified
|
285
283
|
message = "Could not verify Pingpp's SSL certificate. " \
|
286
284
|
"Please make sure that your network is not intercepting certificates. " \
|
287
|
-
"(Try going to (#{@api_base}) in your browser.)
|
288
|
-
"If this problem persists, let us know at support@pingxx.com."
|
285
|
+
"(Try going to (#{@api_base}) in your browser.)"
|
289
286
|
|
290
287
|
when SocketError
|
291
288
|
message = "Unexpected error communicating when trying to connect to Pingpp. " \
|
@@ -293,8 +290,7 @@ module Pingpp
|
|
293
290
|
"To check, try running 'host pingxx.com' from the command line."
|
294
291
|
|
295
292
|
else
|
296
|
-
message = "Unexpected error communicating with Pingpp.
|
297
|
-
"If this problem persists, let us know at support@pingxx.com."
|
293
|
+
message = "Unexpected error communicating with Pingpp."
|
298
294
|
|
299
295
|
end
|
300
296
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pingpp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xufeng Weng
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
@@ -141,7 +141,6 @@ files:
|
|
141
141
|
- lib/pingpp/api_operations/list.rb
|
142
142
|
- lib/pingpp/api_operations/update.rb
|
143
143
|
- lib/pingpp/api_resource.rb
|
144
|
-
- lib/pingpp/certificate_blacklist.rb
|
145
144
|
- lib/pingpp/charge.rb
|
146
145
|
- lib/pingpp/errors/api_connection_error.rb
|
147
146
|
- lib/pingpp/errors/api_error.rb
|
@@ -1,51 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'digest/sha1'
|
3
|
-
|
4
|
-
module Pingpp
|
5
|
-
module CertificateBlacklist
|
6
|
-
|
7
|
-
BLACKLIST = {
|
8
|
-
"api.pingxx.com" => [
|
9
|
-
]
|
10
|
-
}
|
11
|
-
|
12
|
-
# Preflight the SSL certificate presented by the backend. This isn't 100%
|
13
|
-
# bulletproof, in that we're not actually validating the transport used to
|
14
|
-
# communicate with Pingpp, merely that the first attempt to does not use a
|
15
|
-
# revoked certificate.
|
16
|
-
|
17
|
-
# Unfortunately the interface to OpenSSL doesn't make it easy to check the
|
18
|
-
# certificate before sending potentially sensitive data on the wire. This
|
19
|
-
# approach raises the bar for an attacker significantly.
|
20
|
-
|
21
|
-
def self.check_ssl_cert(uri, ca_file)
|
22
|
-
uri = URI.parse(uri)
|
23
|
-
|
24
|
-
sock = TCPSocket.new(uri.host, uri.port)
|
25
|
-
ctx = OpenSSL::SSL::SSLContext.new
|
26
|
-
ctx.set_params(:verify_mode => OpenSSL::SSL::VERIFY_PEER,
|
27
|
-
:ca_file => ca_file)
|
28
|
-
|
29
|
-
socket = OpenSSL::SSL::SSLSocket.new(sock, ctx)
|
30
|
-
socket.connect
|
31
|
-
|
32
|
-
certificate = socket.peer_cert.to_der
|
33
|
-
fingerprint = Digest::SHA1.hexdigest(certificate)
|
34
|
-
|
35
|
-
if blacklisted_certs = BLACKLIST[uri.host]
|
36
|
-
if blacklisted_certs.include?(fingerprint)
|
37
|
-
raise APIConnectionError.new(
|
38
|
-
"Invalid server certificate. You tried to connect to a server that" +
|
39
|
-
"has a revoked SSL certificate, which means we cannot securely send" +
|
40
|
-
"data to that server. Please email support@pingxx.com if you need" +
|
41
|
-
"help connecting to the correct API server."
|
42
|
-
)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
socket.close
|
47
|
-
|
48
|
-
return true
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|