mirror of https://github.com/docusealco/docuseal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
41 lines
1.1 KiB
41 lines
1.1 KiB
# 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
|