add hmac webhook secret
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module WebhookUrls
|
||||
module Signatures
|
||||
SECRET_PREFIX = 'whsec_'
|
||||
SECRET_BYTES = 24
|
||||
TOLERANCE = 5 * 60
|
||||
|
||||
InvalidSignatureError = Class.new(StandardError)
|
||||
TimestampError = Class.new(StandardError)
|
||||
|
||||
module_function
|
||||
|
||||
def generate_secret
|
||||
SECRET_PREFIX + Base64.strict_encode64(SecureRandom.bytes(SECRET_BYTES))
|
||||
end
|
||||
|
||||
def sign(secret, body:, timestamp: Time.current.to_i)
|
||||
"#{timestamp}.#{OpenSSL::HMAC.hexdigest('sha256', secret, "#{timestamp}.#{body}")}"
|
||||
end
|
||||
|
||||
def verify(secret, body:, header:, tolerance: TOLERANCE)
|
||||
ts, sig = header.to_s.split('.', 2)
|
||||
ts = Integer(ts, exception: false)
|
||||
|
||||
raise InvalidSignatureError unless ts && sig
|
||||
|
||||
now = Time.current.to_i
|
||||
|
||||
raise TimestampError, 'Too old' if ts < now - tolerance
|
||||
raise TimestampError, 'In future' if ts > now + tolerance
|
||||
|
||||
expected = OpenSSL::HMAC.hexdigest('sha256', secret, "#{ts}.#{body}")
|
||||
|
||||
raise InvalidSignatureError unless ActiveSupport::SecurityUtils.secure_compare(expected, sig)
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user