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 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.