stripe 2.8.0 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.txt +4 -0
- data/VERSION +1 -1
- data/lib/stripe.rb +4 -1
- data/lib/stripe/account.rb +6 -5
- data/lib/stripe/errors.rb +40 -0
- data/lib/stripe/oauth.rb +56 -0
- data/lib/stripe/stripe_client.rb +44 -12
- data/lib/stripe/version.rb +1 -1
- data/test/stripe/oauth_test.rb +85 -0
- data/test/stripe/stripe_client_test.rb +39 -3
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f9ea5d1ce3e948a439878fadba81ef52b47c24e
|
4
|
+
data.tar.gz: 00d62fe82daf1570ada3004672ddd15b6fe2425b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 227094e5bb975bbd0acaf044d5f3708055fb8c12f043af80dd4851a8a784646f2f506d45c4a87ea166cbae285085623eb7aebb1366a1f5dec035a95437fede56
|
7
|
+
data.tar.gz: 3158ef959bc7d5ed39bc26b9482515b3c8aec2fdf0d96d6f6a87c2481d254517688e994d6b6ea8fd7006a70d809f42af8ab76eb0caa621e6ec1f69bf47a85c9b
|
data/History.txt
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.9.0
|
data/lib/stripe.rb
CHANGED
@@ -69,6 +69,9 @@ require 'stripe/three_d_secure'
|
|
69
69
|
require 'stripe/token'
|
70
70
|
require 'stripe/transfer'
|
71
71
|
|
72
|
+
# OAuth
|
73
|
+
require 'stripe/oauth'
|
74
|
+
|
72
75
|
module Stripe
|
73
76
|
DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/data/ca-certificates.crt'
|
74
77
|
|
@@ -90,7 +93,7 @@ module Stripe
|
|
90
93
|
@read_timeout = 80
|
91
94
|
|
92
95
|
class << self
|
93
|
-
attr_accessor :stripe_account, :api_key, :api_base, :verify_ssl_certs, :api_version, :connect_base, :uploads_base,
|
96
|
+
attr_accessor :stripe_account, :api_key, :api_base, :verify_ssl_certs, :api_version, :client_id, :connect_base, :uploads_base,
|
94
97
|
:open_timeout, :read_timeout
|
95
98
|
|
96
99
|
attr_reader :max_network_retry_delay, :initial_network_retry_delay
|
data/lib/stripe/account.rb
CHANGED
@@ -93,11 +93,12 @@ module Stripe
|
|
93
93
|
raise NoMethodError.new('Overridding legal_entity can cause serious issues. Instead, set the individual fields of legal_entity like blah.legal_entity.first_name = \'Blah\'')
|
94
94
|
end
|
95
95
|
|
96
|
-
def deauthorize(client_id, opts={})
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
96
|
+
def deauthorize(client_id=nil, opts={})
|
97
|
+
params = {
|
98
|
+
client_id: client_id,
|
99
|
+
stripe_user_id: self.id,
|
100
|
+
}
|
101
|
+
OAuth.deauthorize(params, opts)
|
101
102
|
end
|
102
103
|
|
103
104
|
ARGUMENT_NOT_PROVIDED = Object.new
|
data/lib/stripe/errors.rb
CHANGED
@@ -100,4 +100,44 @@ module Stripe
|
|
100
100
|
@sig_header = sig_header
|
101
101
|
end
|
102
102
|
end
|
103
|
+
|
104
|
+
module OAuth
|
105
|
+
# OAuthError is raised when the OAuth API returns an error.
|
106
|
+
class OAuthError < StripeError
|
107
|
+
attr_accessor :code
|
108
|
+
|
109
|
+
def initialize(code, description, http_status: nil, http_body: nil, json_body: nil,
|
110
|
+
http_headers: nil)
|
111
|
+
super(description, http_status: http_status, http_body: http_body,
|
112
|
+
json_body: json_body, http_headers: http_headers)
|
113
|
+
@code = code
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# InvalidGrantError is raised when a specified code doesn't exist, is
|
118
|
+
# expired, has been used, or doesn't belong to you; a refresh token doesn't
|
119
|
+
# exist, or doesn't belong to you; or if an API key's mode (live or test)
|
120
|
+
# doesn't match the mode of a code or refresh token.
|
121
|
+
class InvalidGrantError < OAuthError
|
122
|
+
end
|
123
|
+
|
124
|
+
# InvalidRequestError is raised when a code, refresh token, or grant type
|
125
|
+
# parameter is not provided, but was required.
|
126
|
+
class InvalidRequestError < OAuthError
|
127
|
+
end
|
128
|
+
|
129
|
+
# InvalidScopeError is raised when an invalid scope parameter is provided.
|
130
|
+
class InvalidScopeError < OAuthError
|
131
|
+
end
|
132
|
+
|
133
|
+
# UnsupportedGrantTypeError is raised when an unuspported grant type
|
134
|
+
# parameter is specified.
|
135
|
+
class UnsupportedGrantTypeError < OAuthError
|
136
|
+
end
|
137
|
+
|
138
|
+
# UnsupportedResponseTypeError is raised when an unsupported response type
|
139
|
+
# parameter is specified.
|
140
|
+
class UnsupportedResponseTypeError < OAuthError
|
141
|
+
end
|
142
|
+
end
|
103
143
|
end
|
data/lib/stripe/oauth.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Stripe
|
2
|
+
module OAuth
|
3
|
+
module OAuthOperations
|
4
|
+
extend APIOperations::Request::ClassMethods
|
5
|
+
|
6
|
+
def self.request(method, url, params, opts)
|
7
|
+
opts = Util.normalize_opts(opts)
|
8
|
+
opts[:client] ||= StripeClient.active_client
|
9
|
+
opts[:api_base] ||= Stripe.connect_base
|
10
|
+
|
11
|
+
super(method, url, params, opts)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.get_client_id(params={})
|
16
|
+
client_id = params[:client_id] || Stripe.client_id
|
17
|
+
unless client_id
|
18
|
+
raise AuthenticationError.new('No client_id provided. ' \
|
19
|
+
'Set your client_id using "Stripe.client_id = <CLIENT-ID>". ' \
|
20
|
+
'You can find your client_ids in your Stripe dashboard at ' \
|
21
|
+
'https://dashboard.stripe.com/account/applications/settings, ' \
|
22
|
+
'after registering your account as a platform. See ' \
|
23
|
+
'https://stripe.com/docs/connect/standalone-accounts for details, ' \
|
24
|
+
'or email support@stripe.com if you have any questions.')
|
25
|
+
end
|
26
|
+
client_id
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.authorize_url(params={}, opts={})
|
30
|
+
base = opts[:connect_base] || Stripe.connect_base
|
31
|
+
|
32
|
+
params[:client_id] = get_client_id(params)
|
33
|
+
params[:response_type] ||= 'code'
|
34
|
+
query = Util.encode_parameters(params)
|
35
|
+
|
36
|
+
"#{base}/oauth/authorize?#{query}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.token(params={}, opts={})
|
40
|
+
opts = Util.normalize_opts(opts)
|
41
|
+
resp, opts = OAuthOperations.request(
|
42
|
+
:post, '/oauth/token', params, opts)
|
43
|
+
# This is just going to return a generic StripeObject, but that's okay
|
44
|
+
Util.convert_to_stripe_object(resp.data, opts)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.deauthorize(params={}, opts={})
|
48
|
+
opts = Util.normalize_opts(opts)
|
49
|
+
params[:client_id] = get_client_id(params)
|
50
|
+
resp, opts = OAuthOperations.request(
|
51
|
+
:post, '/oauth/deauthorize', params, opts)
|
52
|
+
# This is just going to return a generic StripeObject, but that's okay
|
53
|
+
Util.convert_to_stripe_object(resp.data, opts)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/stripe/stripe_client.rb
CHANGED
@@ -197,7 +197,7 @@ module Stripe
|
|
197
197
|
case e
|
198
198
|
when Faraday::ClientError
|
199
199
|
if e.response
|
200
|
-
|
200
|
+
handle_error_response(e.response)
|
201
201
|
else
|
202
202
|
handle_network_error(e, retry_count, api_base)
|
203
203
|
end
|
@@ -229,12 +229,12 @@ module Stripe
|
|
229
229
|
str
|
230
230
|
end
|
231
231
|
|
232
|
-
def
|
232
|
+
def handle_error_response(http_resp)
|
233
233
|
begin
|
234
234
|
resp = StripeResponse.from_faraday_hash(http_resp)
|
235
|
-
|
235
|
+
error_data = resp.data[:error]
|
236
236
|
|
237
|
-
unless
|
237
|
+
unless error_data
|
238
238
|
raise StripeError.new("Indeterminate error")
|
239
239
|
end
|
240
240
|
|
@@ -242,47 +242,79 @@ module Stripe
|
|
242
242
|
raise general_api_error(http_resp[:status], http_resp[:body])
|
243
243
|
end
|
244
244
|
|
245
|
+
if error_data.is_a?(String)
|
246
|
+
error = specific_oauth_error(resp, error_data)
|
247
|
+
end
|
248
|
+
if error.nil?
|
249
|
+
error = specific_api_error(resp, error_data)
|
250
|
+
end
|
251
|
+
|
252
|
+
error.response = resp
|
253
|
+
raise(error)
|
254
|
+
end
|
255
|
+
|
256
|
+
def specific_api_error(resp, error_data)
|
245
257
|
case resp.http_status
|
246
258
|
when 400, 404
|
247
259
|
error = InvalidRequestError.new(
|
248
|
-
|
260
|
+
error_data[:message], error_data[:param],
|
249
261
|
http_status: resp.http_status, http_body: resp.http_body,
|
250
262
|
json_body: resp.data, http_headers: resp.http_headers
|
251
263
|
)
|
252
264
|
when 401
|
253
265
|
error = AuthenticationError.new(
|
254
|
-
|
266
|
+
error_data[:message],
|
255
267
|
http_status: resp.http_status, http_body: resp.http_body,
|
256
268
|
json_body: resp.data, http_headers: resp.http_headers
|
257
269
|
)
|
258
270
|
when 402
|
259
271
|
error = CardError.new(
|
260
|
-
|
272
|
+
error_data[:message], error_data[:param], error_data[:code],
|
261
273
|
http_status: resp.http_status, http_body: resp.http_body,
|
262
274
|
json_body: resp.data, http_headers: resp.http_headers
|
263
275
|
)
|
264
276
|
when 403
|
265
277
|
error = PermissionError.new(
|
266
|
-
|
278
|
+
error_data[:message],
|
267
279
|
http_status: resp.http_status, http_body: resp.http_body,
|
268
280
|
json_body: resp.data, http_headers: resp.http_headers
|
269
281
|
)
|
270
282
|
when 429
|
271
283
|
error = RateLimitError.new(
|
272
|
-
|
284
|
+
error_data[:message],
|
273
285
|
http_status: resp.http_status, http_body: resp.http_body,
|
274
286
|
json_body: resp.data, http_headers: resp.http_headers
|
275
287
|
)
|
276
288
|
else
|
277
289
|
error = APIError.new(
|
278
|
-
|
290
|
+
error_data[:message],
|
279
291
|
http_status: resp.http_status, http_body: resp.http_body,
|
280
292
|
json_body: resp.data, http_headers: resp.http_headers
|
281
293
|
)
|
282
294
|
end
|
283
295
|
|
284
|
-
error
|
285
|
-
|
296
|
+
error
|
297
|
+
end
|
298
|
+
|
299
|
+
# Attempts to look at a response's error code and return an OAuth error if
|
300
|
+
# one matches. Will return `nil` if the code isn't recognized.
|
301
|
+
def specific_oauth_error(resp, error_code)
|
302
|
+
description = resp.data[:error_description] || error_code
|
303
|
+
|
304
|
+
args = [error_code, description, {
|
305
|
+
http_status: resp.http_status, http_body: resp.http_body,
|
306
|
+
json_body: resp.data, http_headers: resp.http_headers
|
307
|
+
}]
|
308
|
+
|
309
|
+
case error_code
|
310
|
+
when 'invalid_grant' then OAuth::InvalidGrantError.new(*args)
|
311
|
+
when 'invalid_request' then OAuth::InvalidRequestError.new(*args)
|
312
|
+
when 'invalid_scope' then OAuth::InvalidScopeError.new(*args)
|
313
|
+
when 'unsupported_grant_type' then OAuth::UnsupportedGrantTypeError.new(*args)
|
314
|
+
when 'unsupported_response_type' then OAuth::UnsupportedResponseTypeError.new(*args)
|
315
|
+
else
|
316
|
+
nil
|
317
|
+
end
|
286
318
|
end
|
287
319
|
|
288
320
|
def handle_network_error(e, retry_count, api_base=nil)
|
data/lib/stripe/version.rb
CHANGED
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.expand_path('../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module Stripe
|
4
|
+
class OAuthTest < Test::Unit::TestCase
|
5
|
+
setup do
|
6
|
+
Stripe.client_id = 'ca_test'
|
7
|
+
end
|
8
|
+
|
9
|
+
teardown do
|
10
|
+
Stripe.client_id = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
context ".authorize_url" do
|
14
|
+
should "return the authorize URL" do
|
15
|
+
uri_str = OAuth.authorize_url({
|
16
|
+
scope: 'read_write',
|
17
|
+
state: 'csrf_token',
|
18
|
+
stripe_user: {
|
19
|
+
email: 'test@example.com',
|
20
|
+
url: 'https://example.com/profile/test',
|
21
|
+
country: 'US',
|
22
|
+
},
|
23
|
+
})
|
24
|
+
|
25
|
+
uri = URI::parse(uri_str)
|
26
|
+
params = CGI::parse(uri.query)
|
27
|
+
|
28
|
+
assert_equal('https', uri.scheme)
|
29
|
+
assert_equal('connect.stripe.com', uri.host)
|
30
|
+
assert_equal('/oauth/authorize', uri.path)
|
31
|
+
|
32
|
+
assert_equal(['ca_test'], params['client_id'])
|
33
|
+
assert_equal(['read_write'], params['scope'])
|
34
|
+
assert_equal(['test@example.com'], params['stripe_user[email]'])
|
35
|
+
assert_equal(['https://example.com/profile/test'], params['stripe_user[url]'])
|
36
|
+
assert_equal(['US'], params['stripe_user[country]'])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context ".token" do
|
41
|
+
should "exchange a code for an access token" do
|
42
|
+
# The OpenAPI fixtures don't cover the OAuth endpoints, so we just
|
43
|
+
# stub the request manually.
|
44
|
+
stub_request(:post, "#{Stripe.connect_base}/oauth/token").
|
45
|
+
with(body: {
|
46
|
+
'grant_type' => 'authorization_code',
|
47
|
+
'code' => 'this_is_an_authorization_code',
|
48
|
+
}).
|
49
|
+
to_return(body: JSON.generate({
|
50
|
+
access_token: 'sk_access_token',
|
51
|
+
scope: 'read_only',
|
52
|
+
livemode: false,
|
53
|
+
token_type: 'bearer',
|
54
|
+
refresh_token: 'sk_refresh_token',
|
55
|
+
stripe_user_id: 'acct_test',
|
56
|
+
stripe_publishable_key: 'pk_test',
|
57
|
+
}))
|
58
|
+
|
59
|
+
resp = OAuth.token({
|
60
|
+
grant_type: 'authorization_code',
|
61
|
+
code: 'this_is_an_authorization_code',
|
62
|
+
})
|
63
|
+
assert_equal('sk_access_token', resp.access_token)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context ".deauthorize" do
|
68
|
+
should "deauthorize an account" do
|
69
|
+
# The OpenAPI fixtures don't cover the OAuth endpoints, so we just
|
70
|
+
# stub the request manually.
|
71
|
+
stub_request(:post, "#{Stripe.connect_base}/oauth/deauthorize").
|
72
|
+
with(body: {
|
73
|
+
'client_id' => 'ca_test',
|
74
|
+
'stripe_user_id' => 'acct_test_deauth',
|
75
|
+
}).
|
76
|
+
to_return(body: JSON.generate({
|
77
|
+
stripe_user_id: 'acct_test_deauth',
|
78
|
+
}))
|
79
|
+
|
80
|
+
resp = OAuth.deauthorize({stripe_user_id: 'acct_test_deauth'})
|
81
|
+
assert_equal('acct_test_deauth', resp.stripe_user_id)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -243,16 +243,16 @@ module Stripe
|
|
243
243
|
assert_equal 'Invalid response object from API: "" (HTTP response code was 200)', e.message
|
244
244
|
end
|
245
245
|
|
246
|
-
should "handle error response with
|
246
|
+
should "handle error response with unknown value" do
|
247
247
|
stub_request(:post, "#{Stripe.api_base}/v1/charges").
|
248
|
-
to_return(body: JSON.generate({
|
248
|
+
to_return(body: JSON.generate({ bar: "foo" }), status: 500)
|
249
249
|
|
250
250
|
client = StripeClient.new
|
251
251
|
e = assert_raises Stripe::APIError do
|
252
252
|
client.execute_request(:post, '/v1/charges')
|
253
253
|
end
|
254
254
|
|
255
|
-
assert_equal 'Invalid response object from API: "{\"
|
255
|
+
assert_equal 'Invalid response object from API: "{\"bar\":\"foo\"}" (HTTP response code was 500)', e.message
|
256
256
|
end
|
257
257
|
|
258
258
|
should "raise InvalidRequestError on 400" do
|
@@ -332,6 +332,42 @@ module Stripe
|
|
332
332
|
assert_equal(true, e.json_body.kind_of?(Hash))
|
333
333
|
end
|
334
334
|
end
|
335
|
+
|
336
|
+
should "raise OAuth::InvalidRequestError when error is a string with value 'invalid_request'" do
|
337
|
+
stub_request(:post, "#{Stripe.connect_base}/oauth/token").
|
338
|
+
to_return(body: JSON.generate({
|
339
|
+
error: "invalid_request",
|
340
|
+
error_description: "No grant type specified",
|
341
|
+
}), status: 400)
|
342
|
+
|
343
|
+
client = StripeClient.new
|
344
|
+
opts = {api_base: Stripe.connect_base}
|
345
|
+
e = assert_raises Stripe::OAuth::InvalidRequestError do
|
346
|
+
client.execute_request(:post, '/oauth/token', opts)
|
347
|
+
end
|
348
|
+
|
349
|
+
assert_equal(400, e.http_status)
|
350
|
+
assert_equal(true, !!e.http_body)
|
351
|
+
assert_equal('No grant type specified', e.message)
|
352
|
+
end
|
353
|
+
|
354
|
+
should "raise OAuth::InvalidGrantError when error is a string with value 'invalid_grant'" do
|
355
|
+
stub_request(:post, "#{Stripe.connect_base}/oauth/token").
|
356
|
+
to_return(body: JSON.generate({
|
357
|
+
error: "invalid_grant",
|
358
|
+
error_description: "This authorization code has already been used. All tokens issued with this code have been revoked.",
|
359
|
+
}), status: 400)
|
360
|
+
|
361
|
+
client = StripeClient.new
|
362
|
+
opts = {api_base: Stripe.connect_base}
|
363
|
+
e = assert_raises Stripe::OAuth::InvalidGrantError do
|
364
|
+
client.execute_request(:post, '/oauth/token', opts)
|
365
|
+
end
|
366
|
+
|
367
|
+
assert_equal(400, e.http_status)
|
368
|
+
assert_equal('invalid_grant', e.code)
|
369
|
+
assert_equal('This authorization code has already been used. All tokens issued with this code have been revoked.', e.message)
|
370
|
+
end
|
335
371
|
end
|
336
372
|
|
337
373
|
context "idempotency keys" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stripe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stripe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -75,6 +75,7 @@ files:
|
|
75
75
|
- lib/stripe/invoice_item.rb
|
76
76
|
- lib/stripe/invoice_line_item.rb
|
77
77
|
- lib/stripe/list_object.rb
|
78
|
+
- lib/stripe/oauth.rb
|
78
79
|
- lib/stripe/order.rb
|
79
80
|
- lib/stripe/order_return.rb
|
80
81
|
- lib/stripe/payout.rb
|
@@ -128,6 +129,7 @@ files:
|
|
128
129
|
- test/stripe/invoice_line_item_test.rb
|
129
130
|
- test/stripe/invoice_test.rb
|
130
131
|
- test/stripe/list_object_test.rb
|
132
|
+
- test/stripe/oauth_test.rb
|
131
133
|
- test/stripe/order_return_test.rb
|
132
134
|
- test/stripe/order_test.rb
|
133
135
|
- test/stripe/payout_test.rb
|
@@ -201,6 +203,7 @@ test_files:
|
|
201
203
|
- test/stripe/invoice_line_item_test.rb
|
202
204
|
- test/stripe/invoice_test.rb
|
203
205
|
- test/stripe/list_object_test.rb
|
206
|
+
- test/stripe/oauth_test.rb
|
204
207
|
- test/stripe/order_return_test.rb
|
205
208
|
- test/stripe/order_test.rb
|
206
209
|
- test/stripe/payout_test.rb
|