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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d22d41c56bb85d7b5712eaf36c274b8636f6a5a27b767d344d766ca59b6be4dc
4
- data.tar.gz: ec876e8fcf530e645e4a26bd8dee1c635dee466248d31e7746c33aa4e6373c0e
3
+ metadata.gz: 609a42b37282281ebdaea0fa8e0fd74540cdf49b44df5c3d03fc2c9d05a71638
4
+ data.tar.gz: 88f0c70adfa171e72d448126300692dfb027165fbb8d5be69e2dbf1eb7c2a9a1
5
5
  SHA512:
6
- metadata.gz: 69cdb2b0263d577512d77892a3229b4a8112ccd5c6eae8fb6d38510901981da05d93062dd514a6fa9976d54927f5208a6fdc8f5c2bf6f5db072eaac0089f66a0
7
- data.tar.gz: c681fc11a7566635cdf094ad1bbe1c90db63887ed019d65a25f4eb52efe39411786c370c47403bd2b26f8d5df62f588ba951cf4d59bb12d6f4d3f02cda36a5cf
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.18.0
1
+ 5.19.0
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stripe
4
- VERSION = "5.18.0"
4
+ VERSION = "5.19.0"
5
5
  end
@@ -24,10 +24,20 @@ module Stripe
24
24
  module Signature
25
25
  EXPECTED_SCHEME = "v1"
26
26
 
27
- def self.compute_signature(payload, secret)
28
- OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, payload)
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
- signed_payload = "#{timestamp}.#{payload}"
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.to_f - tolerance
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
@@ -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.to_i
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.send(:compute_signature, "#{opts[:timestamp]}.#{opts[:payload]}", opts[:secret])
21
- "t=#{opts[:timestamp]},#{opts[:scheme]}=#{opts[:signature]}"
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.to_i - 15)
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.18.0
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-22 00:00:00.000000000 Z
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.