Module: Sendly::Webhooks
- Defined in:
- lib/sendly/webhooks.rb
Overview
Webhook utilities for verifying and parsing Sendly webhook events.
Defined Under Namespace
Modules: ListHealthEventSource
Constant Summary collapse
- SIGNATURE_TOLERANCE_SECONDS =
300- EVENT_MESSAGE_QUEUED =
Webhook event type string constants. Use these when subscribing instead of string literals so you catch typos at load time.
"message.queued"- EVENT_MESSAGE_SENT =
"message.sent"- EVENT_MESSAGE_DELIVERED =
"message.delivered"- EVENT_MESSAGE_FAILED =
"message.failed"- EVENT_MESSAGE_BOUNCED =
"message.bounced"- EVENT_MESSAGE_RETRYING =
"message.retrying"- EVENT_MESSAGE_RECEIVED =
"message.received"- EVENT_MESSAGE_OPT_OUT =
"message.opt_out"- EVENT_MESSAGE_OPT_IN =
"message.opt_in"- EVENT_VERIFICATION_CREATED =
"verification.created"- EVENT_VERIFICATION_DELIVERED =
"verification.delivered"- EVENT_VERIFICATION_VERIFIED =
"verification.verified"- EVENT_VERIFICATION_EXPIRED =
"verification.expired"- EVENT_VERIFICATION_FAILED =
"verification.failed"- EVENT_VERIFICATION_RESENT =
"verification.resent"- EVENT_VERIFICATION_DELIVERY_FAILED =
"verification.delivery_failed"- EVENT_CONTACT_AUTO_FLAGGED =
"contact.auto_flagged"- EVENT_CONTACT_MARKED_VALID =
"contact.marked_valid"- EVENT_CONTACTS_LOOKUP_COMPLETED =
"contacts.lookup_completed"- EVENT_CONTACTS_BULK_MARKED_VALID =
"contacts.bulk_marked_valid"
Class Method Summary collapse
-
.generate_signature(payload, secret, timestamp: nil) ⇒ String
Generate a webhook signature for testing purposes.
-
.parse_event(payload, signature, secret, timestamp: nil) ⇒ WebhookEvent
Parse and validate a webhook event.
-
.verify_signature(payload, signature, secret, timestamp: nil) ⇒ Boolean
Verify webhook signature from Sendly.
Class Method Details
.generate_signature(payload, secret, timestamp: nil) ⇒ String
Generate a webhook signature for testing purposes.
126 127 128 129 |
# File 'lib/sendly/webhooks.rb', line 126 def generate_signature(payload, secret, timestamp: nil) signed_payload = ? "#{}.#{payload}" : payload 'sha256=' + OpenSSL::HMAC.hexdigest('SHA256', secret, signed_payload) end |
.parse_event(payload, signature, secret, timestamp: nil) ⇒ WebhookEvent
Parse and validate a webhook event.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/sendly/webhooks.rb', line 104 def parse_event(payload, signature, secret, timestamp: nil) unless verify_signature(payload, signature, secret, timestamp: ) raise WebhookSignatureError, 'Invalid webhook signature' end data = JSON.parse(payload, symbolize_names: true) unless data[:id] && data[:type] && data[:data] raise WebhookSignatureError, 'Invalid event structure' end WebhookEvent.new(data) rescue JSON::ParserError => e raise WebhookSignatureError, "Failed to parse webhook payload: #{e.}" end |
.verify_signature(payload, signature, secret, timestamp: nil) ⇒ Boolean
Verify webhook signature from Sendly.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/sendly/webhooks.rb', line 79 def verify_signature(payload, signature, secret, timestamp: nil) return false if payload.nil? || payload.empty? return false if signature.nil? || signature.empty? return false if secret.nil? || secret.empty? if signed_payload = "#{}.#{payload}" return false if (Time.now.to_i - .to_i).abs > SIGNATURE_TOLERANCE_SECONDS else signed_payload = payload end expected = 'sha256=' + OpenSSL::HMAC.hexdigest('SHA256', secret, signed_payload) secure_compare(expected, signature) end |