Module: Hivehook::Webhook
- Defined in:
- lib/hivehook/webhook.rb
Constant Summary collapse
- HEADER_SIGNATURE =
"X-Hivehook-Signature"- HEADER_TIMESTAMP =
"X-Hivehook-Timestamp"- HEADER_MESSAGE_ID =
"X-Hivehook-Message-ID"
Class Method Summary collapse
-
.extract_v1(signature) ⇒ Object
Parse a multi-scheme signature header value and return the full “v1=…” element, or nil if absent.
- .sign(payload, secret, timestamp) ⇒ Object
-
.verify(payload, secret, signature, timestamp, tolerance_seconds = nil) ⇒ Object
Verify a webhook signature.
- .verify_with_rotation(payload, primary, secondary, signature, timestamp, tolerance_seconds = nil) ⇒ Object
Class Method Details
.extract_v1(signature) ⇒ Object
Parse a multi-scheme signature header value and return the full “v1=…” element, or nil if absent. Supports comma-separated lists like “v1=abc,v2=xyz” or “t=123,v1=abc”.
51 52 53 54 |
# File 'lib/hivehook/webhook.rb', line 51 def self.extract_v1(signature) return nil if signature.nil? signature.split(",").map(&:strip).find { |part| part.start_with?("v1=") } end |
.sign(payload, secret, timestamp) ⇒ Object
11 12 13 14 15 |
# File 'lib/hivehook/webhook.rb', line 11 def self.sign(payload, secret, ) = "#{}.#{payload}" digest = OpenSSL::HMAC.hexdigest("SHA256", secret, ) "v1=#{digest}" end |
.verify(payload, secret, signature, timestamp, tolerance_seconds = nil) ⇒ Object
Verify a webhook signature.
tolerance_seconds semantics:
nil -> skip timestamp check
0 -> strict, any drift fails
positive -> allow past drift up to N seconds, reject future timestamps beyond N seconds
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/hivehook/webhook.rb', line 23 def self.verify(payload, secret, signature, , tolerance_seconds = nil) unless tolerance_seconds.nil? delta = Time.now.to_i - # delta > 0 -> timestamp is in the past # delta < 0 -> timestamp is in the future if delta > tolerance_seconds || -delta > tolerance_seconds return false end end v1 = extract_v1(signature) return false unless v1 expected = sign(payload, secret, ) secure_compare(expected, v1) end |
.verify_with_rotation(payload, primary, secondary, signature, timestamp, tolerance_seconds = nil) ⇒ Object
40 41 42 43 44 45 46 |
# File 'lib/hivehook/webhook.rb', line 40 def self.verify_with_rotation(payload, primary, secondary, signature, , tolerance_seconds = nil) # Compute both verifications without short-circuiting to keep # timing characteristics uniform regardless of which secret matched. primary_ok = verify(payload, primary, signature, , tolerance_seconds) secondary_ok = secondary ? verify(payload, secondary, signature, , tolerance_seconds) : false primary_ok | secondary_ok end |