module Stripe::Webhook::Signature
Constants
- EXPECTED_SCHEME
Public Class Methods
verify_header(payload, header, secret, tolerance: nil)
click to toggle source
Verifies the signature header for a given payload.
Raises a SignatureVerificationError
in the following cases:
-
the header does not match the expected format
-
no signatures found with the expected scheme
-
no signatures matching the expected signature
-
a tolerance is provided and the timestamp is not within the tolerance
Returns true otherwise
# File lib/stripe/webhook.rb, line 52 def self.verify_header(payload, header, secret, tolerance: nil) begin timestamp, signatures = get_timestamp_and_signatures(header, EXPECTED_SCHEME) rescue StandardError raise SignatureVerificationError.new( "Unable to extract timestamp and signatures from header", header, http_body: payload ) end if signatures.empty? raise SignatureVerificationError.new( "No signatures found with expected scheme #{EXPECTED_SCHEME}", header, http_body: payload ) end signed_payload = "#{timestamp}.#{payload}" expected_sig = compute_signature(signed_payload, secret) unless signatures.any? { |s| Util.secure_compare(expected_sig, s) } raise SignatureVerificationError.new( "No signatures found matching the expected signature for payload", header, http_body: payload ) end if tolerance && timestamp < Time.now.to_f - tolerance raise SignatureVerificationError.new( "Timestamp outside the tolerance zone (#{Time.at(timestamp)})", header, http_body: payload ) end true end
Private Class Methods
compute_signature(payload, secret)
click to toggle source
# File lib/stripe/webhook.rb, line 27 def self.compute_signature(payload, secret) OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, payload) end
get_timestamp_and_signatures(header, scheme)
click to toggle source
Extracts the timestamp and the signature(s) with the desired scheme from the header
# File lib/stripe/webhook.rb, line 34 def self.get_timestamp_and_signatures(header, scheme) list_items = header.split(/,\s*/).map { |i| i.split("=", 2) } timestamp = Integer(list_items.select { |i| i[0] == "t" }[0][1]) signatures = list_items.select { |i| i[0] == scheme }.map { |i| i[1] } [timestamp, signatures] end