forked from integrallis/stripe_event
/
webhook_controller_spec.rb
135 lines (105 loc) · 3.96 KB
/
webhook_controller_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
require 'rails_helper'
require 'spec_helper'
describe StripeEvent::WebhookController, type: :controller do
let(:secret1) { 'secret1' }
let(:secret2) { 'secret2' }
let(:charge_succeeded) { stub_event('evt_charge_succeeded') }
def stub_event(identifier)
JSON.parse(File.read("spec/support/fixtures/#{identifier}.json"))
end
def generate_signature(params, secret)
payload = params.to_json
timestamp = Time.now
# compute_signature was private until version 5.19.0 when it was made
# public and had it's API changed to split timestamp to a separate field.
signer = Stripe::Webhook::Signature.method(:compute_signature)
signature =
if signer.arity == 3
signer.call(timestamp, payload, secret)
else
signer.call("#{timestamp.to_i}.#{payload}", secret)
end
"t=#{timestamp.to_i},v1=#{signature}"
end
def webhook(signature, params)
request.env['HTTP_STRIPE_SIGNATURE'] = signature
request.env['RAW_POST_DATA'] = params.to_json # works with Rails 3, 4, or 5
post :event, body: params.to_json
end
def webhook_with_signature(params, secret = secret1)
webhook generate_signature(params, secret), params
end
routes { StripeEvent::Engine.routes }
context "without a signing secret" do
before(:each) { StripeEvent.signing_secret = nil }
it "denies invalid signature" do
webhook "invalid signature", charge_succeeded
expect(response.code).to eq '400'
end
it "denies valid signature" do
webhook_with_signature charge_succeeded
expect(response.code).to eq '400'
end
end
context "with a signing secret" do
before(:each) { StripeEvent.signing_secret = secret1 }
it "denies missing signature" do
webhook nil, charge_succeeded
expect(response.code).to eq '400'
end
it "denies invalid signature" do
webhook "invalid signature", charge_succeeded
expect(response.code).to eq '400'
end
it "denies signature from wrong secret" do
webhook_with_signature charge_succeeded, 'bogus'
expect(response.code).to eq '400'
end
it "succeeds with valid signature from correct secret" do
webhook_with_signature charge_succeeded, secret1
expect(response.code).to eq '200'
end
it "succeeds with valid event data" do
count = 0
StripeEvent.subscribe('charge.succeeded') { |evt| count += 1 }
webhook_with_signature charge_succeeded
expect(response.code).to eq '200'
expect(count).to eq 1
end
it "succeeds when the event_filter returns nil (simulating an ignored webhook event)" do
count = 0
StripeEvent.event_filter = lambda { |event| return nil }
StripeEvent.subscribe('charge.succeeded') { |evt| count += 1 }
webhook_with_signature charge_succeeded
expect(response.code).to eq '200'
expect(count).to eq 0
end
it "ensures user-generated Stripe exceptions pass through" do
StripeEvent.subscribe('charge.succeeded') { |evt| raise Stripe::StripeError, "testing" }
expect { webhook_with_signature(charge_succeeded) }.to raise_error(Stripe::StripeError, /testing/)
end
end
context "with multiple signing secrets" do
before(:each) { StripeEvent.signing_secrets = [secret1, secret2] }
it "denies missing signature" do
webhook nil, charge_succeeded
expect(response.code).to eq '400'
end
it "denies invalid signature" do
webhook "invalid signature", charge_succeeded
expect(response.code).to eq '400'
end
it "denies signature from wrong secret" do
webhook_with_signature charge_succeeded, 'bogus'
expect(response.code).to eq '400'
end
it "succeeds with valid signature from first secret" do
webhook_with_signature charge_succeeded, secret1
expect(response.code).to eq '200'
end
it "succeeds with valid signature from second secret" do
webhook_with_signature charge_succeeded, secret2
expect(response.code).to eq '200'
end
end
end