stripe 5.18.0 → 5.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/VERSION +1 -1
- data/lib/stripe/version.rb +1 -1
- data/lib/stripe/webhook.rb +21 -7
- data/test/stripe/webhook_test.rb +22 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 609a42b37282281ebdaea0fa8e0fd74540cdf49b44df5c3d03fc2c9d05a71638
|
4
|
+
data.tar.gz: 88f0c70adfa171e72d448126300692dfb027165fbb8d5be69e2dbf1eb7c2a9a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a800f54e6335291b9ce91a14d715b9432ebaa04a1145b8616470037972b1c8fb83622ad8226fb03e79ce9350c4b132bb776451da25ed3ca10c8624dfebdef778
|
7
|
+
data.tar.gz: ff25a1a52d03cdf59c16012cacced71952462ef3daff1f7caea9403045a20c8c1343e5252f326ff5182a92075fdfbd92432c4059504b529f5cca41289a110430
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## - 2020-04-24
|
4
|
+
* [#915](https://github.com/stripe/stripe-ruby/pull/915) Expose `Stripe::Webhook.compute_signature` publicly
|
5
|
+
|
3
6
|
## 5.18.0 - 2020-04-22
|
4
7
|
* [#911](https://github.com/stripe/stripe-ruby/pull/911) Add support for `BillingPortal` namespace and `Session` resource and APIs
|
5
8
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
5.
|
1
|
+
5.19.0
|
data/lib/stripe/version.rb
CHANGED
data/lib/stripe/webhook.rb
CHANGED
@@ -24,10 +24,20 @@ module Stripe
|
|
24
24
|
module Signature
|
25
25
|
EXPECTED_SCHEME = "v1"
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
# Computes a webhook signature given a time (probably the current time),
|
28
|
+
# a payload, and a signing secret.
|
29
|
+
def self.compute_signature(timestamp, payload, secret)
|
30
|
+
raise ArgumentError, "timestamp should be an instance of Time" \
|
31
|
+
unless timestamp.is_a?(Time)
|
32
|
+
raise ArgumentError, "payload should be a string" \
|
33
|
+
unless payload.is_a?(String)
|
34
|
+
raise ArgumentError, "secret should be a string" \
|
35
|
+
unless secret.is_a?(String)
|
36
|
+
|
37
|
+
timestamped_payload = "#{timestamp.to_i}.#{payload}"
|
38
|
+
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret,
|
39
|
+
timestamped_payload)
|
29
40
|
end
|
30
|
-
private_class_method :compute_signature
|
31
41
|
|
32
42
|
# Extracts the timestamp and the signature(s) with the desired scheme
|
33
43
|
# from the header
|
@@ -35,7 +45,7 @@ module Stripe
|
|
35
45
|
list_items = header.split(/,\s*/).map { |i| i.split("=", 2) }
|
36
46
|
timestamp = Integer(list_items.select { |i| i[0] == "t" }[0][1])
|
37
47
|
signatures = list_items.select { |i| i[0] == scheme }.map { |i| i[1] }
|
38
|
-
[timestamp, signatures]
|
48
|
+
[Time.at(timestamp), signatures]
|
39
49
|
end
|
40
50
|
private_class_method :get_timestamp_and_signatures
|
41
51
|
|
@@ -53,6 +63,11 @@ module Stripe
|
|
53
63
|
begin
|
54
64
|
timestamp, signatures =
|
55
65
|
get_timestamp_and_signatures(header, EXPECTED_SCHEME)
|
66
|
+
|
67
|
+
# TODO: Try to knock over this blanket rescue as it can unintentionally
|
68
|
+
# swallow many valid errors. Instead, try to validate an incoming
|
69
|
+
# header one piece at a time, and error with a known exception class if
|
70
|
+
# any part is found to be invalid. Rescue that class here.
|
56
71
|
rescue StandardError
|
57
72
|
raise SignatureVerificationError.new(
|
58
73
|
"Unable to extract timestamp and signatures from header",
|
@@ -67,8 +82,7 @@ module Stripe
|
|
67
82
|
)
|
68
83
|
end
|
69
84
|
|
70
|
-
|
71
|
-
expected_sig = compute_signature(signed_payload, secret)
|
85
|
+
expected_sig = compute_signature(timestamp, payload, secret)
|
72
86
|
unless signatures.any? { |s| Util.secure_compare(expected_sig, s) }
|
73
87
|
raise SignatureVerificationError.new(
|
74
88
|
"No signatures found matching the expected signature for payload",
|
@@ -76,7 +90,7 @@ module Stripe
|
|
76
90
|
)
|
77
91
|
end
|
78
92
|
|
79
|
-
if tolerance && timestamp < Time.now
|
93
|
+
if tolerance && timestamp < Time.now - tolerance
|
80
94
|
raise SignatureVerificationError.new(
|
81
95
|
"Timestamp outside the tolerance zone (#{Time.at(timestamp)})",
|
82
96
|
header, http_body: payload
|
data/test/stripe/webhook_test.rb
CHANGED
@@ -13,12 +13,29 @@ module Stripe
|
|
13
13
|
SECRET = "whsec_test_secret"
|
14
14
|
|
15
15
|
def generate_header(opts = {})
|
16
|
-
opts[:timestamp] ||= Time.now
|
16
|
+
opts[:timestamp] ||= Time.now
|
17
17
|
opts[:payload] ||= EVENT_PAYLOAD
|
18
18
|
opts[:secret] ||= SECRET
|
19
19
|
opts[:scheme] ||= Stripe::Webhook::Signature::EXPECTED_SCHEME
|
20
|
-
opts[:signature] ||= Stripe::Webhook::Signature.
|
21
|
-
|
20
|
+
opts[:signature] ||= Stripe::Webhook::Signature.compute_signature(
|
21
|
+
opts[:timestamp],
|
22
|
+
opts[:payload],
|
23
|
+
opts[:secret]
|
24
|
+
)
|
25
|
+
"t=#{opts[:timestamp].to_i},#{opts[:scheme]}=#{opts[:signature]}"
|
26
|
+
end
|
27
|
+
|
28
|
+
context ".compute_signature" do
|
29
|
+
should "compute a signature which can then be verified" do
|
30
|
+
timestamp = Time.now
|
31
|
+
signature = Stripe::Webhook::Signature.compute_signature(
|
32
|
+
timestamp,
|
33
|
+
EVENT_PAYLOAD,
|
34
|
+
SECRET
|
35
|
+
)
|
36
|
+
header = generate_header(timestamp: timestamp, signature: signature)
|
37
|
+
assert(Stripe::Webhook::Signature.verify_header(EVENT_PAYLOAD, header, SECRET))
|
38
|
+
end
|
22
39
|
end
|
23
40
|
|
24
41
|
context ".construct_event" do
|
@@ -70,7 +87,7 @@ module Stripe
|
|
70
87
|
end
|
71
88
|
|
72
89
|
should "raise a SignatureVerificationError when the timestamp is not within the tolerance" do
|
73
|
-
header = generate_header(timestamp: Time.now
|
90
|
+
header = generate_header(timestamp: Time.now - 15)
|
74
91
|
e = assert_raises(Stripe::SignatureVerificationError) do
|
75
92
|
Stripe::Webhook::Signature.verify_header(EVENT_PAYLOAD, header, SECRET, tolerance: 10)
|
76
93
|
end
|
@@ -88,7 +105,7 @@ module Stripe
|
|
88
105
|
end
|
89
106
|
|
90
107
|
should "return true when the header contains a valid signature and the timestamp is off but no tolerance is provided" do
|
91
|
-
header = generate_header(timestamp: 12_345)
|
108
|
+
header = generate_header(timestamp: Time.at(12_345))
|
92
109
|
assert(Stripe::Webhook::Signature.verify_header(EVENT_PAYLOAD, header, SECRET))
|
93
110
|
end
|
94
111
|
end
|
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: 5.
|
4
|
+
version: 5.19.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stripe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-04-
|
11
|
+
date: 2020-04-24 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Stripe is the easiest way to accept payments online. See https://stripe.com
|
14
14
|
for details.
|