Module: AbacatePay::Webhooks
- Defined in:
- lib/abacate_pay/webhooks.rb,
lib/abacate_pay/webhooks/event.rb
Overview
Verification and parsing of inbound AbacatePay webhooks.
Webhook bodies are the least trusted input an integration handles: they arrive unauthenticated on a public endpoint. Every entry point here treats missing, malformed, and hostile input as an expected case and surfaces it as a typed SDK error, never as a raw parser or NoMethodError.
Defined Under Namespace
Classes: Event, PayloadError, SignatureError
Class Method Summary collapse
-
.construct_event(payload:, signature:, secret:) ⇒ Event
Verifies a webhook signature and parses the body in one step.
-
.parse(payload) ⇒ Event
Parses a webhook payload into an Event object.
-
.valid?(payload:, signature:, secret:) ⇒ Boolean
Checks if a webhook signature is valid.
-
.verify!(payload:, signature:, secret:) ⇒ true
Verifies a webhook signature using HMAC-SHA256.
Class Method Details
.construct_event(payload:, signature:, secret:) ⇒ Event
Verifies a webhook signature and parses the body in one step.
This is the only entry point that cannot be used to act on an unauthenticated payload, and is what integrations should call.
81 82 83 84 |
# File 'lib/abacate_pay/webhooks.rb', line 81 def self.construct_event(payload:, signature:, secret:) verify!(payload: payload, signature: signature, secret: secret) parse(payload) end |
.parse(payload) ⇒ Event
Parses a webhook payload into an Event object.
Prefer construct_event, which refuses to parse a body it has not authenticated first.
61 62 63 64 65 66 67 68 |
# File 'lib/abacate_pay/webhooks.rb', line 61 def self.parse(payload) data = JSON.parse(payload.to_s) raise PayloadError, "Expected a JSON object, got #{data.class}" unless data.is_a?(Hash) Event.new(data) rescue JSON::ParserError => e raise PayloadError, "Malformed webhook payload: #{e.}" end |
.valid?(payload:, signature:, secret:) ⇒ Boolean
Checks if a webhook signature is valid.
Never raises for untrusted input — a missing header, an empty secret, or a forged signature all return false.
46 47 48 49 50 51 |
# File 'lib/abacate_pay/webhooks.rb', line 46 def self.valid?(payload:, signature:, secret:) verify!(payload: payload, signature: signature, secret: secret) true rescue SignatureError false end |
.verify!(payload:, signature:, secret:) ⇒ true
Verifies a webhook signature using HMAC-SHA256.
27 28 29 30 31 32 33 34 35 |
# File 'lib/abacate_pay/webhooks.rb', line 27 def self.verify!(payload:, signature:, secret:) raise SignatureError, "Missing webhook signature" if signature.nil? || signature.to_s.empty? raise SignatureError, "Missing webhook secret" if secret.nil? || secret.to_s.empty? expected = OpenSSL::HMAC.hexdigest("SHA256", secret.to_s, payload.to_s) raise SignatureError, "Invalid webhook signature" unless secure_compare(expected, signature.to_s) true end |