stripe 1.30.3 → 2.0.0

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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +4 -0
  3. data/.github/ISSUE_TEMPLATE.md +5 -0
  4. data/.travis.yml +3 -14
  5. data/Gemfile +28 -4
  6. data/History.txt +180 -0
  7. data/README.md +147 -0
  8. data/Rakefile +10 -0
  9. data/VERSION +1 -1
  10. data/bin/stripe-console +12 -5
  11. data/lib/data/ca-certificates.crt +3868 -5114
  12. data/lib/stripe/account.rb +43 -23
  13. data/lib/stripe/alipay_account.rb +20 -0
  14. data/lib/stripe/api_operations/create.rb +2 -2
  15. data/lib/stripe/api_operations/delete.rb +2 -2
  16. data/lib/stripe/api_operations/list.rb +2 -3
  17. data/lib/stripe/api_operations/request.rb +9 -3
  18. data/lib/stripe/api_operations/save.rb +85 -0
  19. data/lib/stripe/api_resource.rb +38 -5
  20. data/lib/stripe/apple_pay_domain.rb +12 -0
  21. data/lib/stripe/application_fee.rb +8 -8
  22. data/lib/stripe/application_fee_refund.rb +7 -3
  23. data/lib/stripe/balance_transaction.rb +1 -1
  24. data/lib/stripe/bank_account.rb +13 -4
  25. data/lib/stripe/bitcoin_receiver.rb +6 -6
  26. data/lib/stripe/bitcoin_transaction.rb +1 -1
  27. data/lib/stripe/card.rb +9 -5
  28. data/lib/stripe/charge.rb +38 -20
  29. data/lib/stripe/country_spec.rb +9 -0
  30. data/lib/stripe/coupon.rb +1 -1
  31. data/lib/stripe/customer.rb +12 -10
  32. data/lib/stripe/dispute.rb +4 -5
  33. data/lib/stripe/errors.rb +92 -0
  34. data/lib/stripe/file_upload.rb +1 -1
  35. data/lib/stripe/invoice.rb +7 -7
  36. data/lib/stripe/invoice_item.rb +1 -1
  37. data/lib/stripe/list_object.rb +8 -7
  38. data/lib/stripe/order.rb +12 -4
  39. data/lib/stripe/order_return.rb +9 -0
  40. data/lib/stripe/plan.rb +1 -1
  41. data/lib/stripe/product.rb +2 -10
  42. data/lib/stripe/recipient.rb +1 -1
  43. data/lib/stripe/refund.rb +1 -1
  44. data/lib/stripe/reversal.rb +7 -3
  45. data/lib/stripe/singleton_api_resource.rb +3 -3
  46. data/lib/stripe/sku.rb +2 -2
  47. data/lib/stripe/source.rb +11 -0
  48. data/lib/stripe/stripe_client.rb +396 -0
  49. data/lib/stripe/stripe_object.rb +167 -91
  50. data/lib/stripe/stripe_response.rb +48 -0
  51. data/lib/stripe/subscription.rb +15 -9
  52. data/lib/stripe/subscription_item.rb +12 -0
  53. data/lib/stripe/three_d_secure.rb +9 -0
  54. data/lib/stripe/transfer.rb +4 -5
  55. data/lib/stripe/util.rb +105 -33
  56. data/lib/stripe/version.rb +1 -1
  57. data/lib/stripe.rb +69 -266
  58. data/spec/fixtures.json +1409 -0
  59. data/spec/fixtures.yaml +1153 -0
  60. data/spec/spec.json +19949 -0
  61. data/spec/spec.yaml +15504 -0
  62. data/stripe.gemspec +5 -18
  63. data/test/api_fixtures.rb +29 -0
  64. data/test/api_stub_helpers.rb +125 -0
  65. data/test/stripe/account_test.rb +163 -211
  66. data/test/stripe/alipay_account_test.rb +19 -0
  67. data/test/stripe/api_operations_test.rb +31 -0
  68. data/test/stripe/api_resource_test.rb +174 -340
  69. data/test/stripe/apple_pay_domain_test.rb +33 -0
  70. data/test/stripe/application_fee_refund_test.rb +22 -31
  71. data/test/stripe/application_fee_test.rb +6 -14
  72. data/test/stripe/balance_test.rb +3 -3
  73. data/test/stripe/bank_account_test.rb +41 -0
  74. data/test/stripe/bitcoin_receiver_test.rb +51 -42
  75. data/test/stripe/bitcoin_transaction_test.rb +11 -19
  76. data/test/stripe/charge_test.rb +39 -98
  77. data/test/stripe/country_spec_test.rb +20 -0
  78. data/test/stripe/coupon_test.rb +35 -11
  79. data/test/stripe/customer_card_test.rb +25 -46
  80. data/test/stripe/customer_test.rb +89 -61
  81. data/test/stripe/dispute_test.rb +28 -31
  82. data/test/stripe/errors_test.rb +18 -0
  83. data/test/stripe/file_upload_test.rb +32 -24
  84. data/test/stripe/invoice_item_test.rb +55 -0
  85. data/test/stripe/invoice_test.rb +50 -24
  86. data/test/stripe/list_object_test.rb +57 -45
  87. data/test/stripe/order_return_test.rb +21 -0
  88. data/test/stripe/order_test.rb +41 -34
  89. data/test/stripe/plan_test.rb +52 -0
  90. data/test/stripe/product_test.rb +31 -25
  91. data/test/stripe/recipient_card_test.rb +23 -40
  92. data/test/stripe/recipient_test.rb +50 -0
  93. data/test/stripe/refund_test.rb +20 -36
  94. data/test/stripe/reversal_test.rb +27 -31
  95. data/test/stripe/sku_test.rb +39 -13
  96. data/test/stripe/source_test.rb +43 -0
  97. data/test/stripe/stripe_client_test.rb +428 -0
  98. data/test/stripe/stripe_object_test.rb +186 -13
  99. data/test/stripe/stripe_response_test.rb +46 -0
  100. data/test/stripe/subscription_item_test.rb +54 -0
  101. data/test/stripe/subscription_test.rb +40 -52
  102. data/test/stripe/three_d_secure_test.rb +23 -0
  103. data/test/stripe/transfer_test.rb +38 -13
  104. data/test/stripe/util_test.rb +48 -16
  105. data/test/stripe_test.rb +25 -0
  106. data/test/test_data.rb +5 -621
  107. data/test/test_helper.rb +24 -24
  108. metadata +60 -139
  109. data/README.rdoc +0 -68
  110. data/gemfiles/default-with-activesupport.gemfile +0 -10
  111. data/gemfiles/json.gemfile +0 -12
  112. data/gemfiles/yajl.gemfile +0 -12
  113. data/lib/stripe/api_operations/update.rb +0 -58
  114. data/lib/stripe/errors/api_connection_error.rb +0 -4
  115. data/lib/stripe/errors/api_error.rb +0 -4
  116. data/lib/stripe/errors/authentication_error.rb +0 -4
  117. data/lib/stripe/errors/card_error.rb +0 -12
  118. data/lib/stripe/errors/invalid_request_error.rb +0 -11
  119. data/lib/stripe/errors/rate_limit_error.rb +0 -4
  120. data/lib/stripe/errors/stripe_error.rb +0 -26
  121. data/test/stripe/charge_refund_test.rb +0 -55
  122. data/test/stripe/metadata_test.rb +0 -129
data/lib/stripe.rb CHANGED
@@ -6,7 +6,7 @@ require 'rbconfig'
6
6
  require 'set'
7
7
  require 'socket'
8
8
 
9
- require 'rest-client'
9
+ require 'faraday'
10
10
  require 'json'
11
11
 
12
12
  # Version
@@ -14,53 +14,56 @@ require 'stripe/version'
14
14
 
15
15
  # API operations
16
16
  require 'stripe/api_operations/create'
17
- require 'stripe/api_operations/update'
17
+ require 'stripe/api_operations/save'
18
18
  require 'stripe/api_operations/delete'
19
19
  require 'stripe/api_operations/list'
20
20
  require 'stripe/api_operations/request'
21
21
 
22
- # Resources
22
+ # API resource support classes
23
+ require 'stripe/errors'
23
24
  require 'stripe/util'
25
+ require 'stripe/stripe_client'
24
26
  require 'stripe/stripe_object'
27
+ require 'stripe/stripe_response'
28
+ require 'stripe/list_object'
25
29
  require 'stripe/api_resource'
26
30
  require 'stripe/singleton_api_resource'
27
- require 'stripe/list_object'
31
+
32
+ # Named API resources
28
33
  require 'stripe/account'
34
+ require 'stripe/alipay_account'
35
+ require 'stripe/apple_pay_domain'
36
+ require 'stripe/application_fee'
37
+ require 'stripe/application_fee_refund'
29
38
  require 'stripe/balance'
30
39
  require 'stripe/balance_transaction'
40
+ require 'stripe/bank_account'
41
+ require 'stripe/bitcoin_receiver'
42
+ require 'stripe/bitcoin_transaction'
43
+ require 'stripe/card'
44
+ require 'stripe/charge'
45
+ require 'stripe/country_spec'
46
+ require 'stripe/coupon'
31
47
  require 'stripe/customer'
48
+ require 'stripe/dispute'
49
+ require 'stripe/event'
50
+ require 'stripe/file_upload'
32
51
  require 'stripe/invoice'
33
52
  require 'stripe/invoice_item'
34
- require 'stripe/charge'
53
+ require 'stripe/order'
54
+ require 'stripe/order_return'
35
55
  require 'stripe/plan'
36
- require 'stripe/file_upload'
37
- require 'stripe/coupon'
38
- require 'stripe/token'
39
- require 'stripe/event'
40
- require 'stripe/transfer'
56
+ require 'stripe/product'
41
57
  require 'stripe/recipient'
42
- require 'stripe/bank_account'
43
- require 'stripe/card'
44
- require 'stripe/subscription'
45
- require 'stripe/application_fee'
46
58
  require 'stripe/refund'
47
59
  require 'stripe/reversal'
48
- require 'stripe/application_fee_refund'
49
- require 'stripe/bitcoin_receiver'
50
- require 'stripe/bitcoin_transaction'
51
- require 'stripe/dispute'
52
- require 'stripe/product'
53
60
  require 'stripe/sku'
54
- require 'stripe/order'
55
-
56
- # Errors
57
- require 'stripe/errors/stripe_error'
58
- require 'stripe/errors/api_error'
59
- require 'stripe/errors/api_connection_error'
60
- require 'stripe/errors/card_error'
61
- require 'stripe/errors/invalid_request_error'
62
- require 'stripe/errors/authentication_error'
63
- require 'stripe/errors/rate_limit_error'
61
+ require 'stripe/source'
62
+ require 'stripe/subscription'
63
+ require 'stripe/subscription_item'
64
+ require 'stripe/three_d_secure'
65
+ require 'stripe/token'
66
+ require 'stripe/transfer'
64
67
 
65
68
  module Stripe
66
69
  DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/data/ca-certificates.crt'
@@ -69,143 +72,65 @@ module Stripe
69
72
  @connect_base = 'https://connect.stripe.com'
70
73
  @uploads_base = 'https://uploads.stripe.com'
71
74
 
72
- @ssl_bundle_path = DEFAULT_CA_BUNDLE_PATH
75
+ @max_network_retries = 0
76
+ @max_network_retry_delay = 2
77
+ @initial_network_retry_delay = 0.5
78
+
79
+ @ca_bundle_path = DEFAULT_CA_BUNDLE_PATH
80
+ @ca_store = nil
73
81
  @verify_ssl_certs = true
74
82
 
75
83
  @open_timeout = 30
76
84
  @read_timeout = 80
77
85
 
78
86
  class << self
79
- attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version, :connect_base, :uploads_base,
87
+ attr_accessor :stripe_account, :api_key, :api_base, :verify_ssl_certs, :api_version, :connect_base, :uploads_base,
80
88
  :open_timeout, :read_timeout
81
- end
82
89
 
83
- def self.api_url(url='', api_base_url=nil)
84
- (api_base_url || @api_base) + url
90
+ attr_reader :max_network_retry_delay, :initial_network_retry_delay
85
91
  end
86
92
 
87
- def self.request(method, url, api_key, params={}, headers={}, api_base_url=nil)
88
- api_base_url = api_base_url || @api_base
89
-
90
- unless api_key ||= @api_key
91
- raise AuthenticationError.new('No API key provided. ' \
92
- 'Set your API key using "Stripe.api_key = <API-KEY>". ' \
93
- 'You can generate API keys from the Stripe web interface. ' \
94
- 'See https://stripe.com/api for details, or email support@stripe.com ' \
95
- 'if you have any questions.')
96
- end
97
-
98
- if api_key =~ /\s/
99
- raise AuthenticationError.new('Your API key is invalid, as it contains ' \
100
- 'whitespace. (HINT: You can double-check your API key from the ' \
101
- 'Stripe web interface. See https://stripe.com/api for details, or ' \
102
- 'email support@stripe.com if you have any questions.)')
103
- end
104
-
105
- if verify_ssl_certs
106
- request_opts = {:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
107
- :ssl_ca_file => @ssl_bundle_path}
108
- else
109
- request_opts = {:verify_ssl => false}
110
- unless @verify_ssl_warned
111
- @verify_ssl_warned = true
112
- $stderr.puts("WARNING: Running without SSL cert verification. " \
113
- "You should never do this in production. " \
114
- "Execute 'Stripe.verify_ssl_certs = true' to enable verification.")
115
- end
116
- end
117
-
118
- params = Util.objects_to_ids(params)
119
- url = api_url(url, api_base_url)
120
-
121
- case method.to_s.downcase.to_sym
122
- when :get, :head, :delete
123
- # Make params into GET parameters
124
- url += "#{URI.parse(url).query ? '&' : '?'}#{Util.encode_parameters(params)}" if params && params.any?
125
- payload = nil
126
- else
127
- if headers[:content_type] && headers[:content_type] == "multipart/form-data"
128
- payload = params
129
- else
130
- payload = Util.encode_parameters(params)
131
- end
132
- end
133
-
134
- request_opts.update(:headers => request_headers(api_key).update(headers),
135
- :method => method, :open_timeout => open_timeout,
136
- :payload => payload, :url => url, :timeout => read_timeout)
137
-
138
- begin
139
- response = execute_request(request_opts)
140
- rescue SocketError => e
141
- handle_restclient_error(e, api_base_url)
142
- rescue NoMethodError => e
143
- # Work around RestClient bug
144
- if e.message =~ /\WRequestFailed\W/
145
- e = APIConnectionError.new('Unexpected HTTP response code')
146
- handle_restclient_error(e, api_base_url)
147
- else
148
- raise
149
- end
150
- rescue RestClient::ExceptionWithResponse => e
151
- if e.response
152
- handle_api_error(e.response)
153
- else
154
- handle_restclient_error(e, api_base_url)
155
- end
156
- rescue RestClient::Exception, Errno::ECONNREFUSED => e
157
- handle_restclient_error(e, api_base_url)
158
- end
159
-
160
- [parse(response), api_key]
93
+ # The location of a file containing a bundle of CA certificates. By default
94
+ # the library will use an included bundle that can successfully validate
95
+ # Stripe certificates.
96
+ def self.ca_bundle_path
97
+ @ca_bundle_path
161
98
  end
162
99
 
163
- private
164
-
165
- def self.user_agent
166
- @uname ||= get_uname
167
- lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
168
-
169
- {
170
- :bindings_version => Stripe::VERSION,
171
- :lang => 'ruby',
172
- :lang_version => lang_version,
173
- :platform => RUBY_PLATFORM,
174
- :engine => defined?(RUBY_ENGINE) ? RUBY_ENGINE : '',
175
- :publisher => 'stripe',
176
- :uname => @uname,
177
- :hostname => Socket.gethostname,
178
- }
100
+ def self.ca_bundle_path=(path)
101
+ @ca_bundle_path = path
179
102
 
103
+ # empty this field so a new store is initialized
104
+ @ca_store = nil
180
105
  end
181
106
 
182
- def self.get_uname
183
- if File.exist?('/proc/version')
184
- File.read('/proc/version').strip
185
- else
186
- case RbConfig::CONFIG['host_os']
187
- when /linux|darwin|bsd|sunos|solaris|cygwin/i
188
- _uname_uname
189
- when /mswin|mingw/i
190
- _uname_ver
191
- else
192
- "unknown platform"
193
- end
107
+ # A certificate store initialized from the the bundle in #ca_bundle_path and
108
+ # which is used to validate TLS on every request.
109
+ #
110
+ # This was added to the give the gem "pseudo thread safety" in that it seems
111
+ # when initiating many parallel requests marshaling the certificate store is
112
+ # the most likely point of failure (see issue #382). Any program attempting
113
+ # to leverage this pseudo safety should make a call to this method (i.e.
114
+ # `Stripe.ca_store`) in their initialization code because it marshals lazily
115
+ # and is itself not thread safe.
116
+ def self.ca_store
117
+ @ca_store ||= begin
118
+ store = OpenSSL::X509::Store.new
119
+ store.add_file(ca_bundle_path)
120
+ store
194
121
  end
195
122
  end
196
123
 
197
- def self._uname_uname
198
- (`uname -a 2>/dev/null` || '').strip
199
- rescue Errno::ENOMEM # couldn't create subprocess
200
- "uname lookup failed"
124
+ def self.max_network_retries
125
+ @max_network_retries
201
126
  end
202
127
 
203
- def self._uname_ver
204
- (`ver` || '').strip
205
- rescue Errno::ENOMEM # couldn't create subprocess
206
- "uname lookup failed"
128
+ def self.max_network_retries=(val)
129
+ @max_network_retries = val.to_i
207
130
  end
208
131
 
132
+ private
133
+
209
134
  # DEPRECATED. Use `Util#encode_parameters` instead.
210
135
  def self.uri_encode(params)
211
136
  Util.encode_parameters(params)
@@ -214,126 +139,4 @@ module Stripe
214
139
  extend Gem::Deprecate
215
140
  deprecate :uri_encode, "Stripe::Util#encode_parameters", 2016, 01
216
141
  end
217
-
218
- def self.request_headers(api_key)
219
- headers = {
220
- :user_agent => "Stripe/v1 RubyBindings/#{Stripe::VERSION}",
221
- :authorization => "Bearer #{api_key}",
222
- :content_type => 'application/x-www-form-urlencoded'
223
- }
224
-
225
- headers[:stripe_version] = api_version if api_version
226
-
227
- begin
228
- headers.update(:x_stripe_client_user_agent => JSON.generate(user_agent))
229
- rescue => e
230
- headers.update(:x_stripe_client_raw_user_agent => user_agent.inspect,
231
- :error => "#{e} (#{e.class})")
232
- end
233
- end
234
-
235
- def self.execute_request(opts)
236
- RestClient::Request.execute(opts)
237
- end
238
-
239
- def self.parse(response)
240
- begin
241
- # Would use :symbolize_names => true, but apparently there is
242
- # some library out there that makes symbolize_names not work.
243
- response = JSON.parse(response.body)
244
- rescue JSON::ParserError
245
- raise general_api_error(response.code, response.body)
246
- end
247
-
248
- Util.symbolize_names(response)
249
- end
250
-
251
- def self.general_api_error(rcode, rbody)
252
- APIError.new("Invalid response object from API: #{rbody.inspect} " +
253
- "(HTTP response code was #{rcode})", rcode, rbody)
254
- end
255
-
256
- def self.handle_api_error(resp)
257
- begin
258
- error_obj = JSON.parse(resp.body)
259
- error_obj = Util.symbolize_names(error_obj)
260
- error = error_obj[:error]
261
- raise StripeError.new unless error && error.is_a?(Hash)
262
-
263
- rescue JSON::ParserError, StripeError
264
- raise general_api_error(resp.code, resp.body)
265
- end
266
-
267
- case resp.code
268
- when 400, 404
269
- raise invalid_request_error(error, resp, error_obj)
270
- when 401
271
- raise authentication_error(error, resp, error_obj)
272
- when 402
273
- raise card_error(error, resp, error_obj)
274
- when 429
275
- raise rate_limit_error(error, resp, error_obj)
276
- else
277
- raise api_error(error, resp, error_obj)
278
- end
279
-
280
- end
281
-
282
- def self.invalid_request_error(error, resp, error_obj)
283
- InvalidRequestError.new(error[:message], error[:param], resp.code,
284
- resp.body, error_obj, resp.headers)
285
- end
286
-
287
- def self.authentication_error(error, resp, error_obj)
288
- AuthenticationError.new(error[:message], resp.code, resp.body, error_obj,
289
- resp.headers)
290
- end
291
-
292
- def self.rate_limit_error(error, resp, error_obj)
293
- RateLimitError.new(error[:message], resp.code, resp.body, error_obj,
294
- resp.headers)
295
- end
296
-
297
- def self.card_error(error, resp, error_obj)
298
- CardError.new(error[:message], error[:param], error[:code],
299
- resp.code, resp.body, error_obj, resp.headers)
300
- end
301
-
302
- def self.api_error(error, resp, error_obj)
303
- APIError.new(error[:message], resp.code, resp.body, error_obj, resp.headers)
304
- end
305
-
306
- def self.handle_restclient_error(e, api_base_url=nil)
307
- api_base_url = @api_base unless api_base_url
308
- connection_message = "Please check your internet connection and try again. " \
309
- "If this problem persists, you should check Stripe's service status at " \
310
- "https://twitter.com/stripestatus, or let us know at support@stripe.com."
311
-
312
- case e
313
- when RestClient::RequestTimeout
314
- message = "Could not connect to Stripe (#{api_base_url}). #{connection_message}"
315
-
316
- when RestClient::ServerBrokeConnection
317
- message = "The connection to the server (#{api_base_url}) broke before the " \
318
- "request completed. #{connection_message}"
319
-
320
- when RestClient::SSLCertificateNotVerified
321
- message = "Could not verify Stripe's SSL certificate. " \
322
- "Please make sure that your network is not intercepting certificates. " \
323
- "(Try going to https://api.stripe.com/v1 in your browser.) " \
324
- "If this problem persists, let us know at support@stripe.com."
325
-
326
- when SocketError
327
- message = "Unexpected error communicating when trying to connect to Stripe. " \
328
- "You may be seeing this message because your DNS is not working. " \
329
- "To check, try running 'host stripe.com' from the command line."
330
-
331
- else
332
- message = "Unexpected error communicating with Stripe. " \
333
- "If this problem persists, let us know at support@stripe.com."
334
-
335
- end
336
-
337
- raise APIConnectionError.new(message + "\n\n(Network error: #{e.message})")
338
- end
339
142
  end