stripe 3.3.2 → 3.4.1
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/.gitignore +1 -0
- data/.rubocop.yml +20 -0
- data/.rubocop_todo.yml +62 -0
- data/.travis.yml +1 -1
- data/Gemfile +19 -12
- data/History.txt +10 -0
- data/README.md +5 -1
- data/Rakefile +8 -5
- data/VERSION +1 -1
- data/bin/stripe-console +2 -2
- data/lib/stripe.rb +72 -74
- data/lib/stripe/account.rb +15 -17
- data/lib/stripe/alipay_account.rb +10 -7
- data/lib/stripe/api_operations/create.rb +1 -1
- data/lib/stripe/api_operations/delete.rb +1 -1
- data/lib/stripe/api_operations/list.rb +2 -2
- data/lib/stripe/api_operations/request.rb +5 -12
- data/lib/stripe/api_operations/save.rb +6 -6
- data/lib/stripe/api_resource.rb +7 -9
- data/lib/stripe/apple_pay_domain.rb +2 -2
- data/lib/stripe/application_fee.rb +5 -5
- data/lib/stripe/application_fee_refund.rb +5 -5
- data/lib/stripe/balance.rb +1 -1
- data/lib/stripe/balance_transaction.rb +2 -2
- data/lib/stripe/bank_account.rb +7 -7
- data/lib/stripe/bitcoin_receiver.rb +4 -2
- data/lib/stripe/bitcoin_transaction.rb +3 -1
- data/lib/stripe/card.rb +5 -5
- data/lib/stripe/charge.rb +18 -18
- data/lib/stripe/country_spec.rb +2 -2
- data/lib/stripe/coupon.rb +1 -1
- data/lib/stripe/customer.rb +23 -23
- data/lib/stripe/dispute.rb +3 -3
- data/lib/stripe/ephemeral_key.rb +4 -4
- data/lib/stripe/errors.rb +4 -4
- data/lib/stripe/event.rb +1 -1
- data/lib/stripe/file_upload.rb +5 -5
- data/lib/stripe/invoice.rb +7 -7
- data/lib/stripe/invoice_item.rb +1 -1
- data/lib/stripe/invoice_line_item.rb +1 -1
- data/lib/stripe/list_object.rb +14 -18
- data/lib/stripe/login_link.rb +3 -3
- data/lib/stripe/oauth.rb +15 -13
- data/lib/stripe/order.rb +5 -5
- data/lib/stripe/order_return.rb +1 -1
- data/lib/stripe/payout.rb +3 -3
- data/lib/stripe/plan.rb +1 -1
- data/lib/stripe/product.rb +1 -1
- data/lib/stripe/recipient.rb +3 -2
- data/lib/stripe/recipient_transfer.rb +1 -2
- data/lib/stripe/refund.rb +1 -1
- data/lib/stripe/reversal.rb +5 -5
- data/lib/stripe/singleton_api_resource.rb +3 -3
- data/lib/stripe/sku.rb +1 -1
- data/lib/stripe/source.rb +13 -10
- data/lib/stripe/stripe_client.rb +149 -169
- data/lib/stripe/stripe_object.rb +77 -76
- data/lib/stripe/subscription.rb +5 -5
- data/lib/stripe/subscription_item.rb +2 -2
- data/lib/stripe/three_d_secure.rb +1 -1
- data/lib/stripe/token.rb +1 -1
- data/lib/stripe/transfer.rb +3 -3
- data/lib/stripe/util.rb +77 -62
- data/lib/stripe/version.rb +1 -1
- data/lib/stripe/webhook.rb +14 -10
- data/stripe.gemspec +14 -14
- data/test/stripe/account_test.rb +69 -81
- data/test/stripe/alipay_account_test.rb +19 -1
- data/test/stripe/api_operations_test.rb +7 -7
- data/test/stripe/api_resource_test.rb +224 -260
- data/test/stripe/apple_pay_domain_test.rb +8 -8
- data/test/stripe/application_fee_refund_test.rb +8 -8
- data/test/stripe/application_fee_test.rb +3 -3
- data/test/stripe/balance_test.rb +2 -2
- data/test/stripe/bank_account_test.rb +9 -11
- data/test/stripe/charge_test.rb +11 -11
- data/test/stripe/country_spec_test.rb +4 -4
- data/test/stripe/coupon_test.rb +10 -10
- data/test/stripe/customer_card_test.rb +11 -15
- data/test/stripe/customer_test.rb +26 -27
- data/test/stripe/dispute_test.rb +8 -8
- data/test/stripe/ephemeral_key_test.rb +14 -14
- data/test/stripe/errors_test.rb +2 -2
- data/test/stripe/file_upload_test.rb +26 -28
- data/test/stripe/invoice_item_test.rb +14 -14
- data/test/stripe/invoice_line_item_test.rb +1 -1
- data/test/stripe/invoice_test.rb +37 -37
- data/test/stripe/list_object_test.rb +60 -76
- data/test/stripe/login_link_test.rb +14 -14
- data/test/stripe/oauth_test.rb +42 -50
- data/test/stripe/order_return_test.rb +5 -5
- data/test/stripe/order_test.rb +12 -12
- data/test/stripe/payout_test.rb +9 -9
- data/test/stripe/plan_test.rb +9 -9
- data/test/stripe/product_test.rb +8 -8
- data/test/stripe/recipient_test.rb +9 -10
- data/test/stripe/refund_test.rb +9 -9
- data/test/stripe/reversal_test.rb +10 -10
- data/test/stripe/sku_test.rb +8 -8
- data/test/stripe/source_test.rb +14 -16
- data/test/stripe/stripe_client_test.rb +235 -266
- data/test/stripe/stripe_object_test.rb +163 -147
- data/test/stripe/stripe_response_test.rb +4 -3
- data/test/stripe/subscription_item_test.rb +11 -11
- data/test/stripe/subscription_test.rb +14 -14
- data/test/stripe/three_d_secure_test.rb +2 -2
- data/test/stripe/transfer_test.rb +8 -8
- data/test/stripe/util_test.rb +59 -57
- data/test/stripe/webhook_test.rb +18 -16
- data/test/stripe_test.rb +4 -4
- data/test/test_data.rb +26 -26
- data/test/test_helper.rb +29 -25
- metadata +6 -10
- data/test/stripe/bitcoin_receiver_test.rb +0 -67
- data/test/stripe/bitcoin_transaction_test.rb +0 -19
- data/test/stripe/recipient_card_test.rb +0 -44
data/lib/stripe/order.rb
CHANGED
@@ -4,14 +4,14 @@ module Stripe
|
|
4
4
|
extend Stripe::APIOperations::Create
|
5
5
|
include Stripe::APIOperations::Save
|
6
6
|
|
7
|
-
OBJECT_NAME =
|
7
|
+
OBJECT_NAME = "order".freeze
|
8
8
|
|
9
|
-
def pay(params, opts={})
|
9
|
+
def pay(params, opts = {})
|
10
10
|
resp, opts = request(:post, pay_url, params, opts)
|
11
11
|
initialize_from(resp.data, opts)
|
12
12
|
end
|
13
13
|
|
14
|
-
def return_order(params, opts={})
|
14
|
+
def return_order(params, opts = {})
|
15
15
|
resp, opts = request(:post, returns_url, params, opts)
|
16
16
|
Util.convert_to_stripe_object(resp.data, opts)
|
17
17
|
end
|
@@ -19,11 +19,11 @@ module Stripe
|
|
19
19
|
private
|
20
20
|
|
21
21
|
def pay_url
|
22
|
-
resource_url +
|
22
|
+
resource_url + "/pay"
|
23
23
|
end
|
24
24
|
|
25
25
|
def returns_url
|
26
|
-
resource_url +
|
26
|
+
resource_url + "/returns"
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
data/lib/stripe/order_return.rb
CHANGED
data/lib/stripe/payout.rb
CHANGED
@@ -4,15 +4,15 @@ module Stripe
|
|
4
4
|
extend Stripe::APIOperations::Create
|
5
5
|
include Stripe::APIOperations::Save
|
6
6
|
|
7
|
-
OBJECT_NAME =
|
7
|
+
OBJECT_NAME = "payout".freeze
|
8
8
|
|
9
9
|
def cancel
|
10
|
-
resp, api_key =
|
10
|
+
resp, api_key = request(:post, cancel_url)
|
11
11
|
initialize_from(resp.data, api_key)
|
12
12
|
end
|
13
13
|
|
14
14
|
def cancel_url
|
15
|
-
resource_url +
|
15
|
+
resource_url + "/cancel"
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
data/lib/stripe/plan.rb
CHANGED
data/lib/stripe/product.rb
CHANGED
data/lib/stripe/recipient.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
module Stripe
|
2
|
+
# Recipients objects are deprecated. Please use Stripe Connect instead.
|
2
3
|
class Recipient < APIResource
|
3
4
|
extend Stripe::APIOperations::Create
|
4
5
|
include Stripe::APIOperations::Delete
|
5
6
|
include Stripe::APIOperations::Save
|
6
7
|
extend Stripe::APIOperations::List
|
7
8
|
|
8
|
-
OBJECT_NAME =
|
9
|
+
OBJECT_NAME = "recipient".freeze
|
9
10
|
|
10
11
|
def transfers
|
11
|
-
Transfer.all({ :
|
12
|
+
Transfer.all({ recipient: id }, @api_key)
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
data/lib/stripe/refund.rb
CHANGED
data/lib/stripe/reversal.rb
CHANGED
@@ -3,18 +3,18 @@ module Stripe
|
|
3
3
|
extend Stripe::APIOperations::List
|
4
4
|
include Stripe::APIOperations::Save
|
5
5
|
|
6
|
-
OBJECT_NAME =
|
6
|
+
OBJECT_NAME = "transfer_reversal".freeze
|
7
7
|
|
8
8
|
def resource_url
|
9
9
|
"#{Transfer.resource_url}/#{CGI.escape(transfer)}/reversals/#{CGI.escape(id)}"
|
10
10
|
end
|
11
11
|
|
12
|
-
def self.update(
|
13
|
-
raise NotImplementedError
|
12
|
+
def self.update(_id, _params = nil, _opts = nil)
|
13
|
+
raise NotImplementedError, "Reversals cannot be updated without a transfer ID. Update a reversal using `r = transfer.reversals.retrieve('reversal_id'); r.save`"
|
14
14
|
end
|
15
15
|
|
16
|
-
def self.retrieve(
|
17
|
-
raise NotImplementedError
|
16
|
+
def self.retrieve(_id, _opts = {})
|
17
|
+
raise NotImplementedError, "Reversals cannot be retrieved without a transfer ID. Retrieve a reversal using transfer.reversals.retrieve('reversal_id')"
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -2,7 +2,7 @@ module Stripe
|
|
2
2
|
class SingletonAPIResource < APIResource
|
3
3
|
def self.resource_url
|
4
4
|
if self == SingletonAPIResource
|
5
|
-
raise NotImplementedError
|
5
|
+
raise NotImplementedError, "SingletonAPIResource is an abstract class. You should perform actions on its subclasses (Account, etc.)"
|
6
6
|
end
|
7
7
|
"/v1/#{CGI.escape(class_name.downcase)}"
|
8
8
|
end
|
@@ -11,8 +11,8 @@ module Stripe
|
|
11
11
|
self.class.resource_url
|
12
12
|
end
|
13
13
|
|
14
|
-
def self.retrieve(opts={})
|
15
|
-
instance =
|
14
|
+
def self.retrieve(opts = {})
|
15
|
+
instance = new(nil, Util.normalize_opts(opts))
|
16
16
|
instance.refresh
|
17
17
|
instance
|
18
18
|
end
|
data/lib/stripe/sku.rb
CHANGED
data/lib/stripe/source.rb
CHANGED
@@ -3,20 +3,23 @@ module Stripe
|
|
3
3
|
extend Stripe::APIOperations::Create
|
4
4
|
include Stripe::APIOperations::Save
|
5
5
|
|
6
|
-
OBJECT_NAME =
|
6
|
+
OBJECT_NAME = "source".freeze
|
7
7
|
|
8
|
-
def delete(params={}, opts={})
|
9
|
-
if respond_to?(:customer)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
raise NotImplementedError.new("Source objects cannot be deleted, they can only be detached from customer objects. This source object does not appear to be currently attached to a customer object.")
|
8
|
+
def delete(params = {}, opts = {})
|
9
|
+
if !respond_to?(:customer) || customer.nil? || customer.empty?
|
10
|
+
raise NotImplementedError,
|
11
|
+
"Source objects cannot be deleted, they can only be detached " \
|
12
|
+
"from customer objects. This source object does not appear to " \
|
13
|
+
"be currently attached to a customer object."
|
15
14
|
end
|
15
|
+
|
16
|
+
url = "#{Customer.resource_url}/#{CGI.escape(customer)}/sources/#{CGI.escape(id)}"
|
17
|
+
resp, opts = request(:delete, url, params, Util.normalize_opts(opts))
|
18
|
+
initialize_from(resp.data, opts)
|
16
19
|
end
|
17
20
|
|
18
|
-
def verify(params={}, opts={})
|
19
|
-
resp, opts = request(:post, resource_url +
|
21
|
+
def verify(params = {}, opts = {})
|
22
|
+
resp, opts = request(:post, resource_url + "/verify", params, Util.normalize_opts(opts))
|
20
23
|
initialize_from(resp.data, opts)
|
21
24
|
end
|
22
25
|
end
|
data/lib/stripe/stripe_client.rb
CHANGED
@@ -79,11 +79,11 @@ module Stripe
|
|
79
79
|
# Apply exponential backoff with initial_network_retry_delay on the
|
80
80
|
# number of num_retries so far as inputs. Do not allow the number to exceed
|
81
81
|
# max_network_retry_delay.
|
82
|
-
sleep_seconds = [Stripe.initial_network_retry_delay * (2
|
82
|
+
sleep_seconds = [Stripe.initial_network_retry_delay * (2**(num_retries - 1)), Stripe.max_network_retry_delay].min
|
83
83
|
|
84
84
|
# Apply some jitter by randomizing the value in the range of (sleep_seconds
|
85
85
|
# / 2) to (sleep_seconds).
|
86
|
-
sleep_seconds
|
86
|
+
sleep_seconds *= (0.5 * (1 + rand))
|
87
87
|
|
88
88
|
# But never sleep less than the base sleep seconds.
|
89
89
|
sleep_seconds = [Stripe.initial_network_retry_delay, sleep_seconds].max
|
@@ -96,13 +96,13 @@ module Stripe
|
|
96
96
|
# client = StripeClient.new
|
97
97
|
# charge, resp = client.request { Charge.create }
|
98
98
|
#
|
99
|
-
def request
|
99
|
+
def request
|
100
100
|
@last_response = nil
|
101
101
|
old_stripe_client = Thread.current[:stripe_client]
|
102
102
|
Thread.current[:stripe_client] = self
|
103
103
|
|
104
104
|
begin
|
105
|
-
res =
|
105
|
+
res = yield
|
106
106
|
[res, @last_response]
|
107
107
|
ensure
|
108
108
|
Thread.current[:stripe_client] = old_stripe_client
|
@@ -110,7 +110,7 @@ module Stripe
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def execute_request(method, path,
|
113
|
-
|
113
|
+
api_base: nil, api_key: nil, headers: {}, params: {})
|
114
114
|
|
115
115
|
api_base ||= Stripe.api_base
|
116
116
|
api_key ||= Stripe.api_key
|
@@ -120,36 +120,38 @@ module Stripe
|
|
120
120
|
params = Util.objects_to_ids(params)
|
121
121
|
url = api_url(path, api_base)
|
122
122
|
|
123
|
+
body = nil
|
124
|
+
query_string = nil
|
125
|
+
|
123
126
|
case method.to_s.downcase.to_sym
|
124
127
|
when :get, :head, :delete
|
125
|
-
|
126
|
-
url += "#{URI.parse(url).query ? '&' : '?'}#{
|
127
|
-
payload = nil
|
128
|
+
query_string = Util.encode_parameters(params) if params && params.any?
|
129
|
+
url += "#{URI.parse(url).query ? '&' : '?'}#{query_string}" unless query_string.nil?
|
128
130
|
else
|
129
|
-
if headers[:content_type] && headers[:content_type] == "multipart/form-data"
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
131
|
+
body = if headers[:content_type] && headers[:content_type] == "multipart/form-data"
|
132
|
+
params
|
133
|
+
else
|
134
|
+
Util.encode_parameters(params)
|
135
|
+
end
|
134
136
|
end
|
135
137
|
|
136
|
-
headers = request_headers(api_key, method)
|
137
|
-
|
138
|
+
headers = request_headers(api_key, method)
|
139
|
+
.update(Util.normalize_headers(headers))
|
138
140
|
|
139
141
|
# stores information on the request we're about to make so that we don't
|
140
142
|
# have to pass as many parameters around for logging.
|
141
|
-
context = RequestLogContext.new
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
143
|
+
context = RequestLogContext.new
|
144
|
+
context.account = headers["Stripe-Account"]
|
145
|
+
context.api_key = api_key
|
146
|
+
context.api_version = headers["Stripe-Version"]
|
147
|
+
context.body = body
|
148
|
+
context.idempotency_key = headers["Idempotency-Key"]
|
149
|
+
context.method = method
|
150
|
+
context.path = path
|
151
|
+
context.query_string = query_string
|
150
152
|
|
151
153
|
http_resp = execute_request_with_rescues(api_base, context) do
|
152
|
-
conn.run_request(method, url,
|
154
|
+
conn.run_request(method, url, body, headers) do |req|
|
153
155
|
req.options.open_timeout = Stripe.open_timeout
|
154
156
|
req.options.timeout = Stripe.read_timeout
|
155
157
|
end
|
@@ -168,40 +170,40 @@ module Stripe
|
|
168
170
|
|
169
171
|
private
|
170
172
|
|
171
|
-
def api_url(url=
|
173
|
+
def api_url(url = "", api_base = nil)
|
172
174
|
(api_base || Stripe.api_base) + url
|
173
175
|
end
|
174
176
|
|
175
177
|
def check_api_key!(api_key)
|
176
178
|
unless api_key
|
177
|
-
raise AuthenticationError
|
179
|
+
raise AuthenticationError, "No API key provided. " \
|
178
180
|
'Set your API key using "Stripe.api_key = <API-KEY>". ' \
|
179
|
-
|
180
|
-
|
181
|
-
|
181
|
+
"You can generate API keys from the Stripe web interface. " \
|
182
|
+
"See https://stripe.com/api for details, or email support@stripe.com " \
|
183
|
+
"if you have any questions."
|
182
184
|
end
|
183
185
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
186
|
+
return unless api_key =~ /\s/
|
187
|
+
|
188
|
+
raise AuthenticationError, "Your API key is invalid, as it contains " \
|
189
|
+
"whitespace. (HINT: You can double-check your API key from the " \
|
190
|
+
"Stripe web interface. See https://stripe.com/api for details, or " \
|
191
|
+
"email support@stripe.com if you have any questions.)"
|
190
192
|
end
|
191
193
|
|
192
|
-
def execute_request_with_rescues(api_base, context
|
194
|
+
def execute_request_with_rescues(api_base, context)
|
193
195
|
num_retries = 0
|
194
196
|
begin
|
195
197
|
request_start = Time.now
|
196
198
|
log_request(context, num_retries)
|
197
|
-
resp =
|
199
|
+
resp = yield
|
198
200
|
context = context.dup_from_response(resp)
|
199
201
|
log_response(context, request_start, resp.status, resp.body)
|
200
202
|
|
201
203
|
# We rescue all exceptions from a request so that we have an easy spot to
|
202
204
|
# implement our retry logic across the board. We'll re-raise if it's a type
|
203
205
|
# of exception that we didn't expect to handle.
|
204
|
-
rescue => e
|
206
|
+
rescue StandardError => e
|
205
207
|
# If we modify context we copy it into a new variable so as not to
|
206
208
|
# taint the original on a retry.
|
207
209
|
error_context = context
|
@@ -209,7 +211,7 @@ module Stripe
|
|
209
211
|
if e.respond_to?(:response) && e.response
|
210
212
|
error_context = context.dup_from_response(e.response)
|
211
213
|
log_response(error_context, request_start,
|
212
|
-
|
214
|
+
e.response[:status], e.response[:body])
|
213
215
|
else
|
214
216
|
log_response_error(error_context, request_start, e)
|
215
217
|
end
|
@@ -239,7 +241,7 @@ module Stripe
|
|
239
241
|
end
|
240
242
|
|
241
243
|
def general_api_error(status, body)
|
242
|
-
APIError.new("Invalid response object from API: #{body.inspect} "
|
244
|
+
APIError.new("Invalid response object from API: #{body.inspect} " \
|
243
245
|
"(HTTP response code was #{status})",
|
244
246
|
http_status: status, http_body: body)
|
245
247
|
end
|
@@ -260,34 +262,30 @@ module Stripe
|
|
260
262
|
resp = StripeResponse.from_faraday_hash(http_resp)
|
261
263
|
error_data = resp.data[:error]
|
262
264
|
|
263
|
-
unless error_data
|
264
|
-
raise StripeError.new("Indeterminate error")
|
265
|
-
end
|
266
|
-
|
265
|
+
raise StripeError, "Indeterminate error" unless error_data
|
267
266
|
rescue JSON::ParserError, StripeError
|
268
267
|
raise general_api_error(http_resp[:status], http_resp[:body])
|
269
268
|
end
|
270
269
|
|
271
|
-
if error_data.is_a?(String)
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
270
|
+
error = if error_data.is_a?(String)
|
271
|
+
specific_oauth_error(resp, error_data, context)
|
272
|
+
else
|
273
|
+
specific_api_error(resp, error_data, context)
|
274
|
+
end
|
276
275
|
|
277
276
|
error.response = resp
|
278
277
|
raise(error)
|
279
278
|
end
|
280
279
|
|
281
280
|
def specific_api_error(resp, error_data, context)
|
282
|
-
Util.log_error(
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
)
|
281
|
+
Util.log_error("Stripe API error",
|
282
|
+
status: resp.http_status,
|
283
|
+
error_code: error_data["code"],
|
284
|
+
error_message: error_data["message"],
|
285
|
+
error_param: error_data["param"],
|
286
|
+
error_type: error_data["type"],
|
287
|
+
idempotency_key: context.idempotency_key,
|
288
|
+
request_id: context.request_id)
|
291
289
|
|
292
290
|
case resp.http_status
|
293
291
|
when 400, 404
|
@@ -336,26 +334,25 @@ module Stripe
|
|
336
334
|
def specific_oauth_error(resp, error_code, context)
|
337
335
|
description = resp.data[:error_description] || error_code
|
338
336
|
|
339
|
-
Util.log_error(
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
)
|
337
|
+
Util.log_error("Stripe OAuth error",
|
338
|
+
status: resp.http_status,
|
339
|
+
error_code: error_code,
|
340
|
+
error_description: description,
|
341
|
+
idempotency_key: context.idempotency_key,
|
342
|
+
request_id: context.request_id)
|
346
343
|
|
347
344
|
args = [error_code, description, {
|
348
345
|
http_status: resp.http_status, http_body: resp.http_body,
|
349
|
-
json_body: resp.data, http_headers: resp.http_headers
|
350
|
-
}]
|
346
|
+
json_body: resp.data, http_headers: resp.http_headers,
|
347
|
+
},]
|
351
348
|
|
352
349
|
case error_code
|
353
|
-
when
|
354
|
-
when
|
355
|
-
when
|
356
|
-
when
|
357
|
-
when
|
358
|
-
when
|
350
|
+
when "invalid_client" then OAuth::InvalidClientError.new(*args)
|
351
|
+
when "invalid_grant" then OAuth::InvalidGrantError.new(*args)
|
352
|
+
when "invalid_request" then OAuth::InvalidRequestError.new(*args)
|
353
|
+
when "invalid_scope" then OAuth::InvalidScopeError.new(*args)
|
354
|
+
when "unsupported_grant_type" then OAuth::UnsupportedGrantTypeError.new(*args)
|
355
|
+
when "unsupported_response_type" then OAuth::UnsupportedResponseTypeError.new(*args)
|
359
356
|
else
|
360
357
|
# We'd prefer that all errors are typed, but we create a generic
|
361
358
|
# OAuthError in case we run into a code that we don't recognize.
|
@@ -363,12 +360,11 @@ module Stripe
|
|
363
360
|
end
|
364
361
|
end
|
365
362
|
|
366
|
-
def handle_network_error(e, context, num_retries, api_base=nil)
|
367
|
-
Util.log_error(
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
)
|
363
|
+
def handle_network_error(e, context, num_retries, api_base = nil)
|
364
|
+
Util.log_error("Stripe network error",
|
365
|
+
error_message: e.message,
|
366
|
+
idempotency_key: context.idempotency_key,
|
367
|
+
request_id: context.request_id)
|
372
368
|
|
373
369
|
case e
|
374
370
|
when Faraday::ConnectionFailed
|
@@ -383,7 +379,7 @@ module Stripe
|
|
383
379
|
"command line."
|
384
380
|
|
385
381
|
when Faraday::TimeoutError
|
386
|
-
api_base
|
382
|
+
api_base ||= Stripe.api_base
|
387
383
|
message = "Could not connect to Stripe (#{api_base}). " \
|
388
384
|
"Please check your internet connection and try again. " \
|
389
385
|
"If this problem persists, you should check Stripe's service status at " \
|
@@ -395,11 +391,9 @@ module Stripe
|
|
395
391
|
|
396
392
|
end
|
397
393
|
|
398
|
-
if num_retries > 0
|
399
|
-
message += " Request was retried #{num_retries} times."
|
400
|
-
end
|
394
|
+
message += " Request was retried #{num_retries} times." if num_retries > 0
|
401
395
|
|
402
|
-
raise APIConnectionError
|
396
|
+
raise APIConnectionError, message + "\n\n(Network error: #{e.message})"
|
403
397
|
end
|
404
398
|
|
405
399
|
def request_headers(api_key, method)
|
@@ -409,28 +403,28 @@ module Stripe
|
|
409
403
|
end
|
410
404
|
|
411
405
|
headers = {
|
412
|
-
|
413
|
-
|
414
|
-
|
406
|
+
"User-Agent" => user_agent,
|
407
|
+
"Authorization" => "Bearer #{api_key}",
|
408
|
+
"Content-Type" => "application/x-www-form-urlencoded",
|
415
409
|
}
|
416
410
|
|
417
411
|
# It is only safe to retry network failures on post and delete
|
418
412
|
# requests if we add an Idempotency-Key header
|
419
|
-
if [
|
420
|
-
headers[
|
413
|
+
if %i[post delete].include?(method) && Stripe.max_network_retries > 0
|
414
|
+
headers["Idempotency-Key"] ||= SecureRandom.uuid
|
421
415
|
end
|
422
416
|
|
423
|
-
headers[
|
424
|
-
headers[
|
417
|
+
headers["Stripe-Version"] = Stripe.api_version if Stripe.api_version
|
418
|
+
headers["Stripe-Account"] = Stripe.stripe_account if Stripe.stripe_account
|
425
419
|
|
426
420
|
user_agent = @system_profiler.user_agent
|
427
421
|
begin
|
428
422
|
headers.update(
|
429
|
-
|
423
|
+
"X-Stripe-Client-User-Agent" => JSON.generate(user_agent)
|
430
424
|
)
|
431
|
-
rescue => e
|
425
|
+
rescue StandardError => e
|
432
426
|
headers.update(
|
433
|
-
|
427
|
+
"X-Stripe-Client-Raw-User-Agent" => user_agent.inspect,
|
434
428
|
:error => "#{e} (#{e.class})"
|
435
429
|
)
|
436
430
|
end
|
@@ -440,54 +434,50 @@ module Stripe
|
|
440
434
|
|
441
435
|
def log_request(context, num_retries)
|
442
436
|
Util.log_info("Request to Stripe API",
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
)
|
437
|
+
account: context.account,
|
438
|
+
api_version: context.api_version,
|
439
|
+
idempotency_key: context.idempotency_key,
|
440
|
+
method: context.method,
|
441
|
+
num_retries: num_retries,
|
442
|
+
path: context.path)
|
450
443
|
Util.log_debug("Request details",
|
451
|
-
|
452
|
-
|
453
|
-
|
444
|
+
body: context.body,
|
445
|
+
idempotency_key: context.idempotency_key,
|
446
|
+
query_string: context.query_string)
|
454
447
|
end
|
455
448
|
private :log_request
|
456
449
|
|
457
450
|
def log_response(context, request_start, status, body)
|
458
451
|
Util.log_info("Response from Stripe API",
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
)
|
452
|
+
account: context.account,
|
453
|
+
api_version: context.api_version,
|
454
|
+
elapsed: Time.now - request_start,
|
455
|
+
idempotency_key: context.idempotency_key,
|
456
|
+
method: context.method,
|
457
|
+
path: context.path,
|
458
|
+
request_id: context.request_id,
|
459
|
+
status: status)
|
468
460
|
Util.log_debug("Response details",
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
end
|
461
|
+
body: body,
|
462
|
+
idempotency_key: context.idempotency_key,
|
463
|
+
request_id: context.request_id)
|
464
|
+
|
465
|
+
return unless context.request_id
|
466
|
+
|
467
|
+
Util.log_debug("Dashboard link for request",
|
468
|
+
idempotency_key: context.idempotency_key,
|
469
|
+
request_id: context.request_id,
|
470
|
+
url: Util.request_id_dashboard_url(context.request_id, context.api_key))
|
480
471
|
end
|
481
472
|
private :log_response
|
482
473
|
|
483
474
|
def log_response_error(context, request_start, e)
|
484
475
|
Util.log_error("Request error",
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
)
|
476
|
+
elapsed: Time.now - request_start,
|
477
|
+
error_message: e.message,
|
478
|
+
idempotency_key: context.idempotency_key,
|
479
|
+
method: context.method,
|
480
|
+
path: context.path)
|
491
481
|
end
|
492
482
|
private :log_response_error
|
493
483
|
|
@@ -495,26 +485,16 @@ module Stripe
|
|
495
485
|
# that we can log certain information. It's useful because it means that we
|
496
486
|
# don't have to pass around as many parameters.
|
497
487
|
class RequestLogContext
|
488
|
+
attr_accessor :body
|
498
489
|
attr_accessor :account
|
499
490
|
attr_accessor :api_key
|
500
491
|
attr_accessor :api_version
|
501
492
|
attr_accessor :idempotency_key
|
502
493
|
attr_accessor :method
|
503
494
|
attr_accessor :path
|
504
|
-
attr_accessor :
|
495
|
+
attr_accessor :query_string
|
505
496
|
attr_accessor :request_id
|
506
497
|
|
507
|
-
def initialize(account: nil, api_key: nil, api_version: nil,
|
508
|
-
idempotency_key: nil, method: nil, path: nil, payload: nil)
|
509
|
-
self.account = account
|
510
|
-
self.api_key = api_key
|
511
|
-
self.api_version = api_version
|
512
|
-
self.idempotency_key = idempotency_key
|
513
|
-
self.method = method
|
514
|
-
self.path = path
|
515
|
-
self.payload = payload
|
516
|
-
end
|
517
|
-
|
518
498
|
# The idea with this method is that we might want to update some of
|
519
499
|
# context information because a response that we've received from the API
|
520
500
|
# contains information that's more authoritative than what we started
|
@@ -528,12 +508,12 @@ module Stripe
|
|
528
508
|
# object with a `headers` method, but on error what it puts into
|
529
509
|
# `e.response` is an untyped `Hash`.
|
530
510
|
headers = if resp.is_a?(Faraday::Response)
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
511
|
+
resp.headers
|
512
|
+
else
|
513
|
+
resp[:headers]
|
514
|
+
end
|
535
515
|
|
536
|
-
context =
|
516
|
+
context = dup
|
537
517
|
context.account = headers["Stripe-Account"]
|
538
518
|
context.api_version = headers["Stripe-Version"]
|
539
519
|
context.idempotency_key = headers["Idempotency-Key"]
|
@@ -546,31 +526,31 @@ module Stripe
|
|
546
526
|
# in so that we can generate a rich user agent header to help debug
|
547
527
|
# integrations.
|
548
528
|
class SystemProfiler
|
549
|
-
def self.
|
550
|
-
if File.exist?(
|
551
|
-
File.read(
|
529
|
+
def self.uname
|
530
|
+
if File.exist?("/proc/version")
|
531
|
+
File.read("/proc/version").strip
|
552
532
|
else
|
553
|
-
case RbConfig::CONFIG[
|
533
|
+
case RbConfig::CONFIG["host_os"]
|
554
534
|
when /linux|darwin|bsd|sunos|solaris|cygwin/i
|
555
|
-
|
535
|
+
uname_from_system
|
556
536
|
when /mswin|mingw/i
|
557
|
-
|
537
|
+
uname_from_system_ver
|
558
538
|
else
|
559
539
|
"unknown platform"
|
560
540
|
end
|
561
541
|
end
|
562
542
|
end
|
563
543
|
|
564
|
-
def self.
|
565
|
-
(`uname -a 2>/dev/null` ||
|
544
|
+
def self.uname_from_system
|
545
|
+
(`uname -a 2>/dev/null` || "").strip
|
566
546
|
rescue Errno::ENOENT
|
567
547
|
"uname executable not found"
|
568
548
|
rescue Errno::ENOMEM # couldn't create subprocess
|
569
549
|
"uname lookup failed"
|
570
550
|
end
|
571
551
|
|
572
|
-
def self.
|
573
|
-
(`ver` ||
|
552
|
+
def self.uname_from_system_ver
|
553
|
+
(`ver` || "").strip
|
574
554
|
rescue Errno::ENOENT
|
575
555
|
"ver executable not found"
|
576
556
|
rescue Errno::ENOMEM # couldn't create subprocess
|
@@ -578,23 +558,23 @@ module Stripe
|
|
578
558
|
end
|
579
559
|
|
580
560
|
def initialize
|
581
|
-
@uname = self.class.
|
561
|
+
@uname = self.class.uname
|
582
562
|
end
|
583
563
|
|
584
564
|
def user_agent
|
585
565
|
lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
|
586
566
|
|
587
567
|
{
|
588
|
-
:
|
589
|
-
:
|
590
|
-
:
|
591
|
-
:
|
592
|
-
:
|
593
|
-
:
|
594
|
-
:
|
595
|
-
:
|
596
|
-
:
|
597
|
-
}.delete_if { |
|
568
|
+
application: Stripe.app_info,
|
569
|
+
bindings_version: Stripe::VERSION,
|
570
|
+
lang: "ruby",
|
571
|
+
lang_version: lang_version,
|
572
|
+
platform: RUBY_PLATFORM,
|
573
|
+
engine: defined?(RUBY_ENGINE) ? RUBY_ENGINE : "",
|
574
|
+
publisher: "stripe",
|
575
|
+
uname: @uname,
|
576
|
+
hostname: Socket.gethostname,
|
577
|
+
}.delete_if { |_k, v| v.nil? }
|
598
578
|
end
|
599
579
|
end
|
600
580
|
end
|