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.
@@ -1,3 +1,3 @@
1
1
  module Pingpp
2
- VERSION = '2.0.8'
2
+ VERSION = '2.0.11'
3
3
  end
data/lib/pingpp.rb CHANGED
@@ -3,8 +3,9 @@
3
3
  require 'cgi'
4
4
  require 'set'
5
5
  require 'openssl'
6
- require 'rest_client'
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-06-03'
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
- request_opts = { :verify_ssl => false, :ssl_version => 'TLSv1' }
96
-
97
- if ssl_preflight_passed?
98
- request_opts.update(:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
99
- :ssl_ca_file => @ssl_bundle_path)
100
- end
101
-
102
- if @verify_ssl_certs and !@CERTIFICATE_VERIFIED
103
- @CERTIFICATE_VERIFIED = CertificateBlacklist.check_ssl_cert(@api_base, @ssl_bundle_path)
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://pingxx.com, or let us know at support@pingxx.com."
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.8
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: 2015-07-13 00:00:00.000000000 Z
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