Module: Whatsapp::WebhookSignature
- Defined in:
- lib/whatsapp/webhook_signature.rb
Overview
HMAC-SHA256 signature generation and verification for webhook payloads.
When Configuration#webhook_secret is set, the bridge signs all outgoing WebSocket events and the Rails middleware rejects payloads with missing or invalid signatures.
Constant Summary collapse
- HEADER =
"X-Whatsapp-Signature".freeze
Class Method Summary collapse
-
.secure_compare(a, b) ⇒ Boolean
Constant-time string comparison to prevent timing attacks.
-
.sign(payload, secret) ⇒ String
Sign a payload with HMAC-SHA256.
-
.valid?(payload, signature, secret) ⇒ Boolean
Verify a signature against a payload.
-
.verify!(payload, signature, secret) ⇒ true
Verify a signature, raising on failure.
Class Method Details
.secure_compare(a, b) ⇒ Boolean
Constant-time string comparison to prevent timing attacks.
61 62 63 64 65 |
# File 'lib/whatsapp/webhook_signature.rb', line 61 def self.secure_compare(a, b) return false unless a.bytesize == b.bytesize OpenSSL.fixed_length_secure_compare(a, b) end |
.sign(payload, secret) ⇒ String
Sign a payload with HMAC-SHA256.
24 25 26 27 |
# File 'lib/whatsapp/webhook_signature.rb', line 24 def self.sign(payload, secret) digest = OpenSSL::HMAC.hexdigest("SHA256", secret, payload) "sha256=#{digest}" end |
.valid?(payload, signature, secret) ⇒ Boolean
Verify a signature against a payload.
35 36 37 38 39 40 |
# File 'lib/whatsapp/webhook_signature.rb', line 35 def self.valid?(payload, signature, secret) return false if signature.nil? || signature.empty? expected = sign(payload, secret) secure_compare(expected, signature) end |
.verify!(payload, signature, secret) ⇒ true
Verify a signature, raising on failure.
49 50 51 52 53 54 |
# File 'lib/whatsapp/webhook_signature.rb', line 49 def self.verify!(payload, signature, secret) raise WebhookSignatureError, "Missing webhook signature" if signature.nil? || signature.empty? raise WebhookSignatureError, "Invalid webhook signature" unless valid?(payload, signature, secret) true end |