stripe 5.18.0 → 5.19.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 +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.
|