stripe-rails 1.4.2 → 1.5.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.
- checksums.yaml +4 -4
- data/Changelog.md +5 -0
- data/README.md +55 -0
- data/app/controllers/stripe/events_controller.rb +7 -1
- data/app/models/stripe/event_dispatch.rb +16 -7
- data/lib/stripe/engine.rb +1 -1
- data/lib/stripe/plans.rb +21 -20
- data/lib/stripe/rails/version.rb +1 -1
- data/test/dummy_stripes_controller_spec.rb +2 -0
- data/test/events_controller_spec.rb +33 -2
- data/test/plan_builder_spec.rb +5 -12
- data/test/spec_helper.rb +6 -0
- data/test/stripe_initializers_spec.rb +3 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fbadf81c0f8478feeffda1a46ed1b29b7fd5771eec9fbec5f2a8cd0684a051f
|
4
|
+
data.tar.gz: baa6413f94ecc16b4ac4ba192e29dc7ef3c5742de759ed1e22397a13e71b764e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca51fc8a16bac65cd5ecda5d92130ecf18e83870cacc3c422952846d61359f89ecb877151b4ff9ea93c0e1b25746dd9efe6f86d6790a363de0ede13e6727a9c3
|
7
|
+
data.tar.gz: 7b380bb3b762c6acc39de20b4d0187c15623dc3141adda0bed62d0017a533ccbb546ba4352682d903dae04bf567f504f0a8eb27487b3ab2327d21f1fe973cb41
|
data/Changelog.md
CHANGED
data/README.md
CHANGED
@@ -212,6 +212,61 @@ config.stripe.endpoint = '/payment/stripe-integration'
|
|
212
212
|
|
213
213
|
Your new webhook URL would then be `http://myproductionapp/payment/stripe-integration/events`
|
214
214
|
|
215
|
+
### Signed Webhooks
|
216
|
+
|
217
|
+
Validation of your webhook's signature uses your webhook endpoint signing secret.
|
218
|
+
Before you can verify signatures, you need to retrieve your endpoint’s secret your
|
219
|
+
Stripe Dashboard. Select an endpoint for which you want to obtain
|
220
|
+
the secret, then select the Click to reveal button.
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
# config/application.rb
|
224
|
+
# ...
|
225
|
+
config.stripe.signing_secret = 'whsec_XXXYYYZZZ'
|
226
|
+
```
|
227
|
+
|
228
|
+
Each secret is unique to the endpoint to which it corresponds. If you use multiple endpoints,
|
229
|
+
you must obtain a secret for each one. After this setup, Stripe starts to sign each webhook
|
230
|
+
it sends to the endpoint. Because of this, we recommend setting this variable with an environment
|
231
|
+
variable:
|
232
|
+
|
233
|
+
```sh
|
234
|
+
export STRIPE_SIGNING_SECRET=whsec_XXXYYYZZZ
|
235
|
+
```
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
config.stripe.signing_secret = ENV.fetch('STRIPE_SIGNING_SECRET')
|
239
|
+
```
|
240
|
+
|
241
|
+
#### Testing Signed Webhooks Locally
|
242
|
+
|
243
|
+
In order to test signed webhooks, you'll need to trigger test webhooks from your Stripe dashboard,
|
244
|
+
and configure your local environment to receive remote network requests. To do so, we recommend using
|
245
|
+
[ngrok](https://ngrok.com/) to configure a secure tunnel to `localhost`.
|
246
|
+
|
247
|
+
Once configured and running, `ngrok` will give you a unique URL which can be used to set up a webhook
|
248
|
+
endpoint. Webhook endpoints are configured in your Dashboard's [Webhook settings](https://dashboard.stripe.com/account/webhooks)
|
249
|
+
section. Make sure you are in **Test** mode and click `Add endpoint`, and provide your `ngrok` URL along with the `stripe.endpoint` suffix.
|
250
|
+
|
251
|
+
An example webhook URL would then be `https://bf2a5d21.ngrok.io/stripe/events`.
|
252
|
+
|
253
|
+
Once your endpoint is configured, you can reveal the **Signing secret**. This will need to be set
|
254
|
+
as documented above:
|
255
|
+
|
256
|
+
```ruby
|
257
|
+
# config/application.rb
|
258
|
+
# ...
|
259
|
+
config.stripe.signing_secret = 'whsec_XXXYYYZZZ'
|
260
|
+
```
|
261
|
+
|
262
|
+
And you'll need to restart your rails server with:
|
263
|
+
|
264
|
+
```sh
|
265
|
+
rails restart
|
266
|
+
```
|
267
|
+
|
268
|
+
Now you're ready to click **Send test webhook**, and trigger whichever events you'd like to test from Stripe itself.
|
269
|
+
|
215
270
|
### Disabling auto mount
|
216
271
|
|
217
272
|
Sometimes, you don't want the stripe engine to be auto-mounted so that
|
@@ -4,8 +4,14 @@ module Stripe
|
|
4
4
|
respond_to :json
|
5
5
|
|
6
6
|
def create
|
7
|
-
@event = dispatch_stripe_event
|
7
|
+
@event = dispatch_stripe_event(request)
|
8
8
|
head :ok
|
9
|
+
rescue JSON::ParserError => e
|
10
|
+
::Rails.logger.error e.message
|
11
|
+
head :bad_request, status: 400
|
12
|
+
rescue Stripe::SignatureVerificationError => e
|
13
|
+
::Rails.logger.error e.message
|
14
|
+
head :bad_request, status: 400
|
9
15
|
end
|
10
16
|
end
|
11
17
|
end
|
@@ -1,20 +1,29 @@
|
|
1
1
|
require 'stripe/event'
|
2
2
|
module Stripe
|
3
3
|
module EventDispatch
|
4
|
-
def dispatch_stripe_event(
|
5
|
-
retrieve_stripe_event(
|
4
|
+
def dispatch_stripe_event(request)
|
5
|
+
retrieve_stripe_event(request) do |evt|
|
6
6
|
target = evt.data.object
|
7
7
|
::Stripe::Callbacks.run_callbacks(evt, target)
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
def retrieve_stripe_event(
|
12
|
-
id =
|
13
|
-
|
14
|
-
|
11
|
+
def retrieve_stripe_event(request)
|
12
|
+
id = request['id']
|
13
|
+
body = request.body.read
|
14
|
+
sig_header = request.headers['HTTP_STRIPE_SIGNATURE']
|
15
|
+
endpoint_secret = ::Rails.application.config.stripe.signing_secret
|
16
|
+
|
17
|
+
# this is a webhook test
|
18
|
+
if id == 'evt_00000000000000'
|
19
|
+
event = Stripe::Event.construct_from(JSON.parse(body))
|
20
|
+
elsif Object.const_defined?('Stripe::Webhook') && sig_header && endpoint_secret
|
21
|
+
event = ::Stripe::Webhook.construct_event(body, sig_header, endpoint_secret)
|
15
22
|
else
|
16
|
-
|
23
|
+
event = Stripe::Event.retrieve(id)
|
17
24
|
end
|
25
|
+
|
26
|
+
yield event
|
18
27
|
end
|
19
28
|
end
|
20
29
|
end
|
data/lib/stripe/engine.rb
CHANGED
@@ -8,7 +8,7 @@ module Stripe
|
|
8
8
|
attr_accessor :testing
|
9
9
|
end
|
10
10
|
|
11
|
-
stripe_config = config.stripe = Struct.new(:api_base, :api_version, :secret_key, :verify_ssl_certs, :publishable_key, :endpoint, :debug_js, :auto_mount, :eager_load, :open_timeout, :read_timeout).new
|
11
|
+
stripe_config = config.stripe = Struct.new(:api_base, :api_version, :secret_key, :verify_ssl_certs, :signing_secret, :publishable_key, :endpoint, :debug_js, :auto_mount, :eager_load, :open_timeout, :read_timeout).new
|
12
12
|
|
13
13
|
def stripe_config.api_key=(key)
|
14
14
|
warn "[DEPRECATION] to align with stripe nomenclature, stripe.api_key has been renamed to config.stripe.secret_key"
|
data/lib/stripe/plans.rb
CHANGED
@@ -22,10 +22,10 @@ module Stripe
|
|
22
22
|
validates_presence_of :id, :amount, :currency
|
23
23
|
|
24
24
|
validates_inclusion_of :interval,
|
25
|
-
:
|
26
|
-
:
|
25
|
+
in: %w(day week month year),
|
26
|
+
message: "'%{value}' is not one of 'day', 'week', 'month' or 'year'"
|
27
27
|
|
28
|
-
validates :statement_descriptor, :
|
28
|
+
validates :statement_descriptor, length: { maximum: 22 }
|
29
29
|
|
30
30
|
validates :active, inclusion: { in: [true, false] }, allow_nil: true
|
31
31
|
validates :usage_type, inclusion: { in: %w{ metered licensed } }, allow_nil: true
|
@@ -62,31 +62,32 @@ module Stripe
|
|
62
62
|
|
63
63
|
def default_create_options
|
64
64
|
{
|
65
|
-
:
|
65
|
+
currency: currency,
|
66
66
|
product: product_options,
|
67
|
-
:
|
68
|
-
:
|
69
|
-
:
|
70
|
-
:
|
71
|
-
:
|
72
|
-
|
67
|
+
amount: amount,
|
68
|
+
interval: interval,
|
69
|
+
interval_count: interval_count,
|
70
|
+
trial_period_days: trial_period_days,
|
71
|
+
metadata: metadata,
|
72
|
+
nickname: nickname
|
73
|
+
}.delete_if{|_, v| v.nil? }
|
73
74
|
end
|
74
75
|
|
75
76
|
def product_options
|
76
|
-
|
77
|
+
product_id.presence || { name: name, statement_descriptor: statement_descriptor }
|
77
78
|
end
|
78
79
|
|
79
80
|
def create_options_without_products
|
80
81
|
{
|
81
|
-
:
|
82
|
-
:
|
83
|
-
:
|
84
|
-
:
|
85
|
-
:
|
86
|
-
:
|
87
|
-
:
|
88
|
-
:
|
89
|
-
}
|
82
|
+
currency: currency,
|
83
|
+
name: name,
|
84
|
+
amount: amount,
|
85
|
+
interval: interval,
|
86
|
+
interval_count: interval_count,
|
87
|
+
trial_period_days: trial_period_days,
|
88
|
+
metadata: metadata,
|
89
|
+
statement_descriptor: statement_descriptor
|
90
|
+
}.delete_if{|_, v| v.nil? }
|
90
91
|
end
|
91
92
|
end
|
92
93
|
end
|
data/lib/stripe/rails/version.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Stripe::EventsController do
|
4
|
-
parallelize_me!
|
5
4
|
include Rack::Test::Methods
|
6
5
|
|
7
6
|
let(:app) { Rails.application }
|
@@ -11,7 +10,7 @@ describe Stripe::EventsController do
|
|
11
10
|
end
|
12
11
|
|
13
12
|
describe 'the events interface' do
|
14
|
-
let(:params) {
|
13
|
+
let(:params) {
|
15
14
|
{
|
16
15
|
id: 'evt_00000000000000',
|
17
16
|
type: 'customer.updated',
|
@@ -22,4 +21,36 @@ describe Stripe::EventsController do
|
|
22
21
|
|
23
22
|
it { subject.must_be :ok? }
|
24
23
|
end
|
24
|
+
|
25
|
+
describe 'signed webhooks' do
|
26
|
+
before do
|
27
|
+
header 'Stripe-Signature', 't=1537832721,v1=123,v0=123'
|
28
|
+
app.config.stripe.signing_secret = 'SECRET'
|
29
|
+
end
|
30
|
+
|
31
|
+
after { app.config.stripe.signing_secret = nil }
|
32
|
+
|
33
|
+
let(:params) {
|
34
|
+
{
|
35
|
+
id: 'evt_00000000000001',
|
36
|
+
type: 'customer.updated',
|
37
|
+
data: {
|
38
|
+
object: 'customer',
|
39
|
+
fingerprint: 'xxxyyyzzz'
|
40
|
+
},
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
subject { post '/stripe/events', params.to_json }
|
45
|
+
|
46
|
+
it 'returns bad_request when invalid' do
|
47
|
+
Stripe::Webhook.expects(:construct_event).raises(Stripe::SignatureVerificationError.new('msg', 'sig_header'))
|
48
|
+
subject.must_be :bad_request?
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'returns ok when valid' do
|
52
|
+
Stripe::Webhook.expects(:construct_event).returns(Stripe::Event.construct_from(params))
|
53
|
+
subject.must_be :ok?
|
54
|
+
end
|
55
|
+
end
|
25
56
|
end
|
data/test/plan_builder_spec.rb
CHANGED
@@ -218,9 +218,7 @@ describe 'building plans' do
|
|
218
218
|
:amount => 699,
|
219
219
|
:interval => 'month',
|
220
220
|
:interval_count => 1,
|
221
|
-
:trial_period_days => 0
|
222
|
-
:metadata => nil,
|
223
|
-
:statement_descriptor => nil
|
221
|
+
:trial_period_days => 0
|
224
222
|
)
|
225
223
|
Stripe::Plans::GOLD.put!
|
226
224
|
end
|
@@ -233,9 +231,7 @@ describe 'building plans' do
|
|
233
231
|
:amount => 699,
|
234
232
|
:interval => 'month',
|
235
233
|
:interval_count => 1,
|
236
|
-
:trial_period_days => 0
|
237
|
-
:metadata => nil,
|
238
|
-
:statement_descriptor => nil
|
234
|
+
:trial_period_days => 0
|
239
235
|
)
|
240
236
|
Stripe::Plans::ALTERNATIVE_CURRENCY.put!
|
241
237
|
end
|
@@ -255,8 +251,7 @@ describe 'building plans' do
|
|
255
251
|
:amount => 699,
|
256
252
|
:interval => 'month',
|
257
253
|
:interval_count => 1,
|
258
|
-
:trial_period_days => 0
|
259
|
-
:metadata => nil,
|
254
|
+
:trial_period_days => 0
|
260
255
|
)
|
261
256
|
Stripe::Plans::GOLD.put!
|
262
257
|
end
|
@@ -279,8 +274,7 @@ describe 'building plans' do
|
|
279
274
|
:amount => 699,
|
280
275
|
:interval => 'month',
|
281
276
|
:interval_count => 1,
|
282
|
-
:trial_period_days => 0
|
283
|
-
:metadata => nil,
|
277
|
+
:trial_period_days => 0
|
284
278
|
)
|
285
279
|
Stripe::Plans::GOLD.put!
|
286
280
|
end
|
@@ -303,8 +297,7 @@ describe 'building plans' do
|
|
303
297
|
:amount => 699,
|
304
298
|
:interval => 'month',
|
305
299
|
:interval_count => 1,
|
306
|
-
:trial_period_days => 0
|
307
|
-
:metadata => nil,
|
300
|
+
:trial_period_days => 0
|
308
301
|
)
|
309
302
|
|
310
303
|
subject
|
data/test/spec_helper.rb
CHANGED
@@ -8,7 +8,13 @@ require 'minitest/autorun'
|
|
8
8
|
require 'webmock/minitest'
|
9
9
|
WebMock.disable_net_connect!(allow_localhost: true)
|
10
10
|
|
11
|
+
# Chrome Setup
|
11
12
|
require 'selenium-webdriver'
|
13
|
+
require 'capybara'
|
14
|
+
require 'chromedriver-helper'
|
15
|
+
Capybara.register_driver :selenium do |app|
|
16
|
+
Capybara::Selenium::Driver.new(app, :browser => :chrome)
|
17
|
+
end
|
12
18
|
|
13
19
|
# Configure Rails Environment
|
14
20
|
ENV["RAILS_ENV"] = "test"
|
@@ -34,6 +34,7 @@ describe "Configuring the stripe engine" do
|
|
34
34
|
subject do
|
35
35
|
app.config.stripe.api_base = 'http://localhost:5000'
|
36
36
|
app.config.stripe.secret_key = 'SECRET_XYZ'
|
37
|
+
app.config.stripe.signing_secret = 'SIGNING_SECRET_XYZ'
|
37
38
|
app.config.stripe.verify_ssl_certs = false
|
38
39
|
app.config.stripe.api_version = '2015-10-16'
|
39
40
|
app.config.stripe.open_timeout = 33
|
@@ -50,6 +51,8 @@ describe "Configuring the stripe engine" do
|
|
50
51
|
Stripe.api_version.must_equal '2015-10-16'
|
51
52
|
Stripe.open_timeout.must_equal 33
|
52
53
|
Stripe.read_timeout.must_equal 88
|
54
|
+
|
55
|
+
app.config.stripe.signing_secret.must_equal 'SIGNING_SECRET_XYZ'
|
53
56
|
end
|
54
57
|
end
|
55
58
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stripe-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Lowell
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2018-09-
|
13
|
+
date: 2018-09-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
@@ -178,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
178
178
|
version: '0'
|
179
179
|
requirements: []
|
180
180
|
rubyforge_project:
|
181
|
-
rubygems_version: 2.7.
|
181
|
+
rubygems_version: 2.7.7
|
182
182
|
signing_key:
|
183
183
|
specification_version: 4
|
184
184
|
summary: A gem to integrate stripe into your rails app
|