stripe 1.8.1 → 1.8.2
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.
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/History.txt +14 -0
- data/README.rdoc +10 -0
- data/VERSION +1 -1
- data/lib/stripe.rb +145 -127
- data/lib/stripe/api_operations/update.rb +1 -0
- data/lib/stripe/customer.rb +4 -0
- data/lib/stripe/stripe_object.rb +1 -2
- data/lib/stripe/version.rb +1 -1
- data/test/test_stripe.rb +17 -1
- metadata +3 -2
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
=== 1.8.2 2013-05-01
|
2
|
+
|
3
|
+
* 3 minor enhancement:
|
4
|
+
* Use to_sym instead of type checking for minor performance
|
5
|
+
improvement (github issue #59)
|
6
|
+
* Handle low-memory situations without throwing an exception (github
|
7
|
+
issue #61)
|
8
|
+
* Add an Customer#upcoming_invoice convenience method (github issue
|
9
|
+
#65)
|
10
|
+
|
11
|
+
* 1 bugfix:
|
12
|
+
* Allow updating resources without first retrieving them (github
|
13
|
+
issue #60)
|
14
|
+
|
1
15
|
=== 1.8.1 2013-04-19
|
2
16
|
|
3
17
|
* 1 minor enhancement:
|
data/README.rdoc
CHANGED
@@ -23,6 +23,16 @@ The stripe gem is mirrored on Rubygems, so you should be able to
|
|
23
23
|
install it via <tt>gem install stripe</tt> if desired. We recommend using
|
24
24
|
the https://code.stripe.com mirror so all code is fetched over SSL.
|
25
25
|
|
26
|
+
Note that if you are installing via bundler, you should be sure to use the https
|
27
|
+
rubygems source in your Gemfile, as any gems fetched over http could potentially be
|
28
|
+
comprimised in transit and alter the code of gems fetched securely over https:
|
29
|
+
|
30
|
+
source 'https://code.stripe.com'
|
31
|
+
source 'https://rubygems.org'
|
32
|
+
|
33
|
+
gem 'rails'
|
34
|
+
gem 'stripe'
|
35
|
+
|
26
36
|
== Development
|
27
37
|
|
28
38
|
Test cases can be run with: `bundle exec rake test`
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.8.
|
1
|
+
1.8.2
|
data/lib/stripe.rb
CHANGED
@@ -43,163 +43,164 @@ require 'stripe/errors/invalid_request_error'
|
|
43
43
|
require 'stripe/errors/authentication_error'
|
44
44
|
|
45
45
|
module Stripe
|
46
|
-
|
47
|
-
@@api_key = nil
|
48
|
-
@@api_base = 'https://api.stripe.com'
|
49
|
-
@@verify_ssl_certs = true
|
50
|
-
@@api_version = nil
|
46
|
+
@api_base = 'https://api.stripe.com'
|
51
47
|
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.api_key=(api_key)
|
57
|
-
@@api_key = api_key
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.api_key
|
61
|
-
@@api_key
|
62
|
-
end
|
48
|
+
@ssl_bundle_path = File.dirname(__FILE__) + '/data/ca-certificates.crt'
|
49
|
+
@verify_ssl_certs = true
|
63
50
|
|
64
|
-
|
65
|
-
|
51
|
+
class << self
|
52
|
+
attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version
|
66
53
|
end
|
67
54
|
|
68
|
-
def self.
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
def self.verify_ssl_certs=(verify)
|
73
|
-
@@verify_ssl_certs = verify
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.verify_ssl_certs
|
77
|
-
@@verify_ssl_certs
|
55
|
+
def self.api_url(url='')
|
56
|
+
@api_base + url
|
78
57
|
end
|
79
58
|
|
80
|
-
def self.
|
81
|
-
|
82
|
-
|
59
|
+
def self.request(method, url, api_key, params={}, headers={})
|
60
|
+
unless api_key ||= @api_key
|
61
|
+
raise AuthenticationError.new('No API key provided. ' +
|
62
|
+
'Set your API key using "Stripe.api_key = <API-KEY>". ' +
|
63
|
+
'You can generate API keys from the Stripe web interface. ' +
|
64
|
+
'See https://stripe.com/api for details, or email support@stripe.com ' +
|
65
|
+
'if you have any questions.')
|
66
|
+
end
|
83
67
|
|
84
|
-
|
85
|
-
|
86
|
-
|
68
|
+
if api_key =~ /\s/
|
69
|
+
raise AuthenticationError.new('Your API key is invalid, as it contains ' +
|
70
|
+
'whitespace. (HINT: You can double-check your API key from the ' +
|
71
|
+
'Stripe web interface. See https://stripe.com/api for details, or ' +
|
72
|
+
'email support@stripe.com if you have any questions.)')
|
73
|
+
end
|
87
74
|
|
88
|
-
|
89
|
-
api_key ||= @@api_key
|
90
|
-
raise AuthenticationError.new('No API key provided. (HINT: set your API key using "Stripe.api_key = <API-KEY>". You can generate API keys from the Stripe web interface. See https://stripe.com/api for details, or email support@stripe.com if you have any questions.)') unless api_key
|
75
|
+
request_opts = { :verify_ssl => false }
|
91
76
|
|
92
|
-
if
|
93
|
-
|
94
|
-
|
95
|
-
@no_verify = true
|
96
|
-
end
|
97
|
-
ssl_opts = { :verify_ssl => false }
|
98
|
-
elsif !Util.file_readable(@@ssl_bundle_path)
|
99
|
-
unless @no_bundle
|
100
|
-
$stderr.puts "WARNING: Running without SSL cert verification because #{@@ssl_bundle_path} isn't readable"
|
101
|
-
@no_bundle = true
|
102
|
-
end
|
103
|
-
ssl_opts = { :verify_ssl => false }
|
104
|
-
else
|
105
|
-
ssl_opts = {
|
106
|
-
:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
|
107
|
-
:ssl_ca_file => @@ssl_bundle_path
|
108
|
-
}
|
77
|
+
if ssl_preflight_passed?
|
78
|
+
request_opts.update(:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
|
79
|
+
:ssl_ca_file => @ssl_bundle_path)
|
109
80
|
end
|
110
|
-
uname = (@@uname ||= RUBY_PLATFORM =~ /linux|darwin/i ? `uname -a 2>/dev/null`.strip : nil)
|
111
|
-
lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
|
112
|
-
ua = {
|
113
|
-
:bindings_version => Stripe::VERSION,
|
114
|
-
:lang => 'ruby',
|
115
|
-
:lang_version => lang_version,
|
116
|
-
:platform => RUBY_PLATFORM,
|
117
|
-
:publisher => 'stripe',
|
118
|
-
:uname => uname
|
119
|
-
}
|
120
81
|
|
121
82
|
params = Util.objects_to_ids(params)
|
122
|
-
url =
|
83
|
+
url = api_url(url)
|
84
|
+
|
123
85
|
case method.to_s.downcase.to_sym
|
124
86
|
when :get, :head, :delete
|
125
87
|
# Make params into GET parameters
|
126
|
-
if params && params.
|
127
|
-
query_string = Util.flatten_params(params).collect{|key, value| "#{key}=#{Util.url_encode(value)}"}.join('&')
|
128
|
-
url += "#{URI.parse(url).query ? '&' : '?'}#{query_string}"
|
129
|
-
end
|
88
|
+
url += "#{URI.parse(url).query ? '&' : '?'}#{uri_encode(params)}" if params && params.any?
|
130
89
|
payload = nil
|
131
90
|
else
|
132
|
-
payload =
|
91
|
+
payload = uri_encode(params)
|
133
92
|
end
|
134
93
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
headers = {
|
139
|
-
:x_stripe_client_raw_user_agent => ua.inspect,
|
140
|
-
:error => "#{e} (#{e.class})"
|
141
|
-
}.merge(headers)
|
142
|
-
end
|
143
|
-
|
144
|
-
headers = {
|
145
|
-
:user_agent => "Stripe/v1 RubyBindings/#{Stripe::VERSION}",
|
146
|
-
:authorization => "Bearer #{api_key}",
|
147
|
-
:content_type => 'application/x-www-form-urlencoded'
|
148
|
-
}.merge(headers)
|
149
|
-
|
150
|
-
if self.api_version
|
151
|
-
headers[:stripe_version] = self.api_version
|
152
|
-
end
|
153
|
-
|
154
|
-
opts = {
|
155
|
-
:method => method,
|
156
|
-
:url => url,
|
157
|
-
:headers => headers,
|
158
|
-
:open_timeout => 30,
|
159
|
-
:payload => payload,
|
160
|
-
:timeout => 80
|
161
|
-
}.merge(ssl_opts)
|
94
|
+
request_opts.update(:headers => request_headers.update(headers),
|
95
|
+
:method => method, :open_timeout => 30,
|
96
|
+
:payload => payload, :url => url, :timeout => 80)
|
162
97
|
|
163
98
|
begin
|
164
|
-
response = execute_request(
|
99
|
+
response = execute_request(request_opts)
|
165
100
|
rescue SocketError => e
|
166
|
-
|
101
|
+
handle_restclient_error(e)
|
167
102
|
rescue NoMethodError => e
|
168
103
|
# Work around RestClient bug
|
169
104
|
if e.message =~ /\WRequestFailed\W/
|
170
105
|
e = APIConnectionError.new('Unexpected HTTP response code')
|
171
|
-
|
106
|
+
handle_restclient_error(e)
|
172
107
|
else
|
173
108
|
raise
|
174
109
|
end
|
175
110
|
rescue RestClient::ExceptionWithResponse => e
|
176
111
|
if rcode = e.http_code and rbody = e.http_body
|
177
|
-
|
112
|
+
handle_api_error(rcode, rbody)
|
178
113
|
else
|
179
|
-
|
114
|
+
handle_restclient_error(e)
|
180
115
|
end
|
181
116
|
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
182
|
-
|
117
|
+
handle_restclient_error(e)
|
183
118
|
end
|
184
119
|
|
185
|
-
|
186
|
-
|
120
|
+
parse(response)
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def self.ssl_preflight_passed?
|
126
|
+
if !verify_ssl_certs && !@no_verify
|
127
|
+
$stderr.puts "WARNING: Running without SSL cert verification. " +
|
128
|
+
"Execute 'Stripe.verify_ssl_certs = true' to enable verification."
|
129
|
+
|
130
|
+
@no_verify = true
|
131
|
+
|
132
|
+
elsif !Util.file_readable(@ssl_bundle_path) && !@no_bundle
|
133
|
+
$stderr.puts "WARNING: Running without SSL cert verification " +
|
134
|
+
"because #{@ssl_bundle_path} isn't readable"
|
135
|
+
|
136
|
+
@no_bundle = true
|
137
|
+
end
|
138
|
+
|
139
|
+
!(@no_verify || @no_nobundle)
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.user_agent
|
143
|
+
@uname ||= get_uname
|
144
|
+
lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
|
145
|
+
|
146
|
+
{
|
147
|
+
:bindings_version => Stripe::VERSION,
|
148
|
+
:lang => 'ruby',
|
149
|
+
:lang_version => lang_version,
|
150
|
+
:platform => RUBY_PLATFORM,
|
151
|
+
:publisher => 'stripe',
|
152
|
+
:uname => @uname
|
153
|
+
}
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.get_uname
|
158
|
+
`uname -a 2>/dev/null`.strip if RUBY_PLATFORM =~ /linux|darwin/i
|
159
|
+
rescue Errno::ENOMEM => ex # couldn't create subprocess
|
160
|
+
"uname lookup failed"
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.uri_encode(params)
|
164
|
+
Util.flatten_params(params).
|
165
|
+
map { |k,v| "#{k}=#{Util.url_encode(v)}" }.join('&')
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.request_headers
|
169
|
+
headers = {
|
170
|
+
:user_agent => "Stripe/v1 RubyBindings/#{Stripe::VERSION}",
|
171
|
+
:authorization => "Bearer #{api_key}",
|
172
|
+
:content_type => 'application/x-www-form-urlencoded'
|
173
|
+
}
|
174
|
+
|
175
|
+
headers[:stripe_version] = api_version if api_version
|
176
|
+
|
177
|
+
begin
|
178
|
+
headers.update(:x_stripe_client_user_agent => Stripe::JSON.dump(user_agent))
|
179
|
+
rescue => e
|
180
|
+
headers.update(:x_stripe_client_raw_user_agent => user_agent.inspect,
|
181
|
+
:error => "#{e} (#{e.class})")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.execute_request(opts)
|
186
|
+
RestClient::Request.execute(opts)
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.parse(response)
|
187
190
|
begin
|
188
191
|
# Would use :symbolize_names => true, but apparently there is
|
189
192
|
# some library out there that makes symbolize_names not work.
|
190
|
-
|
193
|
+
response = Stripe::JSON.load(response.body)
|
191
194
|
rescue MultiJson::DecodeError
|
192
|
-
raise
|
195
|
+
raise general_api_error(response.code, response.body)
|
193
196
|
end
|
194
197
|
|
195
|
-
|
196
|
-
[resp, api_key]
|
198
|
+
[Util.symbolize_names(response), api_key]
|
197
199
|
end
|
198
200
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
RestClient::Request.execute(opts)
|
201
|
+
def self.general_api_error(rcode, rbody)
|
202
|
+
APIError.new("Invalid response object from API: #{rbody.inspect} " +
|
203
|
+
"(HTTP response code was #{rcode})", rcode, rbody)
|
203
204
|
end
|
204
205
|
|
205
206
|
def self.handle_api_error(rcode, rbody)
|
@@ -207,24 +208,27 @@ module Stripe
|
|
207
208
|
error_obj = Stripe::JSON.load(rbody)
|
208
209
|
error_obj = Util.symbolize_names(error_obj)
|
209
210
|
error = error_obj[:error] or raise StripeError.new # escape from parsing
|
211
|
+
|
210
212
|
rescue MultiJson::DecodeError, StripeError
|
211
|
-
raise
|
213
|
+
raise general_api_error(rcode, rbody)
|
212
214
|
end
|
213
215
|
|
214
216
|
case rcode
|
215
|
-
when 400, 404
|
216
|
-
raise invalid_request_error
|
217
|
+
when 400, 404
|
218
|
+
raise invalid_request_error error, rcode, rbody, error_obj
|
217
219
|
when 401
|
218
|
-
raise authentication_error
|
220
|
+
raise authentication_error error, rcode, rbody, error_obj
|
219
221
|
when 402
|
220
|
-
raise card_error
|
222
|
+
raise card_error error, rcode, rbody, error_obj
|
221
223
|
else
|
222
|
-
raise api_error
|
224
|
+
raise api_error error, rcode, rbody, error_obj
|
223
225
|
end
|
226
|
+
|
224
227
|
end
|
225
228
|
|
226
229
|
def self.invalid_request_error(error, rcode, rbody, error_obj)
|
227
|
-
InvalidRequestError.new(error[:message], error[:param], rcode,
|
230
|
+
InvalidRequestError.new(error[:message], error[:param], rcode,
|
231
|
+
rbody, error_obj)
|
228
232
|
end
|
229
233
|
|
230
234
|
def self.authentication_error(error, rcode, rbody, error_obj)
|
@@ -232,7 +236,8 @@ module Stripe
|
|
232
236
|
end
|
233
237
|
|
234
238
|
def self.card_error(error, rcode, rbody, error_obj)
|
235
|
-
CardError.new(error[:message], error[:param], error[:code],
|
239
|
+
CardError.new(error[:message], error[:param], error[:code],
|
240
|
+
rcode, rbody, error_obj)
|
236
241
|
end
|
237
242
|
|
238
243
|
def self.api_error(error, rcode, rbody, error_obj)
|
@@ -242,15 +247,28 @@ module Stripe
|
|
242
247
|
def self.handle_restclient_error(e)
|
243
248
|
case e
|
244
249
|
when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
|
245
|
-
message = "Could not connect to Stripe (#{
|
250
|
+
message = "Could not connect to Stripe (#{@api_base}). " +
|
251
|
+
"Please check your internet connection and try again. " +
|
252
|
+
"If this problem persists, you should check Stripe's service status at " +
|
253
|
+
"https://twitter.com/stripestatus, or let us know at support@stripe.com."
|
254
|
+
|
246
255
|
when RestClient::SSLCertificateNotVerified
|
247
|
-
message = "Could not verify Stripe's SSL certificate.
|
256
|
+
message = "Could not verify Stripe's SSL certificate. " +
|
257
|
+
"Please make sure that your network is not intercepting certificates. " +
|
258
|
+
"(Try going to https://api.stripe.com/v1 in your browser.) " +
|
259
|
+
"If this problem persists, let us know at support@stripe.com."
|
260
|
+
|
248
261
|
when SocketError
|
249
|
-
message = "Unexpected error communicating when trying to connect to Stripe.
|
262
|
+
message = "Unexpected error communicating when trying to connect to Stripe. " +
|
263
|
+
"You may be seeing this message because your DNS is not working. " +
|
264
|
+
"To check, try running 'host stripe.com' from the command line."
|
265
|
+
|
250
266
|
else
|
251
|
-
message = "Unexpected error communicating with Stripe.
|
267
|
+
message = "Unexpected error communicating with Stripe. " +
|
268
|
+
"If this problem persists, let us know at support@stripe.com."
|
269
|
+
|
252
270
|
end
|
253
|
-
|
254
|
-
raise APIConnectionError.new(message)
|
271
|
+
|
272
|
+
raise APIConnectionError.new(message + "\n\n(Network error: #{e.message})")
|
255
273
|
end
|
256
274
|
end
|
data/lib/stripe/customer.rb
CHANGED
data/lib/stripe/stripe_object.rb
CHANGED
data/lib/stripe/version.rb
CHANGED
data/test/test_stripe.rb
CHANGED
@@ -81,6 +81,13 @@ class TestStripeRuby < Test::Unit::TestCase
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
+
should "specifying api credentials containing whitespace should raise an exception" do
|
85
|
+
Stripe.api_key = "key "
|
86
|
+
assert_raises Stripe::AuthenticationError do
|
87
|
+
Stripe::Customer.new("test_customer").refresh
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
84
91
|
should "specifying invalid api credentials should raise an exception" do
|
85
92
|
Stripe.api_key = "invalid"
|
86
93
|
response = test_response(test_invalid_api_key_error, 401)
|
@@ -431,7 +438,7 @@ class TestStripeRuby < Test::Unit::TestCase
|
|
431
438
|
c = Stripe::Customer.retrieve("test_customer")
|
432
439
|
|
433
440
|
# Not an accurate response, but whatever
|
434
|
-
|
441
|
+
|
435
442
|
@mock.expects(:delete).once.with("#{Stripe.api_base}/v1/customers/c_test_customer/subscription?at_period_end=true", nil, nil).returns(test_response(test_subscription('silver')))
|
436
443
|
s = c.cancel_subscription({:at_period_end => 'true'})
|
437
444
|
|
@@ -447,6 +454,15 @@ class TestStripeRuby < Test::Unit::TestCase
|
|
447
454
|
s = c.delete_discount
|
448
455
|
assert_equal nil, c.discount
|
449
456
|
end
|
457
|
+
|
458
|
+
should "be able to update a customer without refreshing it first" do
|
459
|
+
@mock.expects(:post).once.with("#{Stripe.api_base}/v1/customers/test_customer", nil, 'mnemonic=bar').returns(test_response(test_customer({:mnemonic => "bar"})))
|
460
|
+
c = Stripe::Customer.new("test_customer")
|
461
|
+
c.mnemonic = "bar"
|
462
|
+
c.save
|
463
|
+
assert_equal c.mnemonic, "bar"
|
464
|
+
end
|
465
|
+
|
450
466
|
end
|
451
467
|
|
452
468
|
context "card tests" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stripe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.8.
|
4
|
+
version: 1.8.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-05-01 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rest-client
|
@@ -199,3 +199,4 @@ test_files:
|
|
199
199
|
- test/test_helper.rb
|
200
200
|
- test/test_stripe.rb
|
201
201
|
- test/test_stripe_with_active_support.rb
|
202
|
+
has_rdoc:
|