Module: OpenWire::Webhook
- Defined in:
- lib/open_wire/webhook.rb
Overview
Verify and parse inbound POSTs from the Open-Wire gateway.
Constant Summary collapse
- HEADER_PROTOCOL =
"X-Open-Wire-Protocol"- HEADER_INSTALLATION =
"X-Open-Wire-Installation"- HEADER_SECRET =
"X-Open-Wire-Secret"
Class Method Summary collapse
- .normalize_headers(headers) ⇒ Object
- .secure_compare(a, b) ⇒ Object
-
.verify_and_parse!(opts) ⇒ Object
opts: secret: expected webhook secret (required unless allow_missing_secret) body: raw request body string OR already-parsed Hash headers: Hash-like (Rack env or ActionDispatch headers).
Class Method Details
.normalize_headers(headers) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/open_wire/webhook.rb', line 33 def normalize_headers(headers) out = {} headers.each do |key, value| name = key.to_s name = name.sub(/\AHTTP_/, "").tr("_", "-") if name.start_with?("HTTP_") out[name.downcase] = value.to_s out[name] = value.to_s end # ActionDispatch::Http::Headers style if headers.respond_to?(:[]) [HEADER_SECRET, HEADER_PROTOCOL, HEADER_INSTALLATION].each do |h| val = headers[h] || headers[h.downcase] out[h.downcase] = val.to_s if val out[h] = val.to_s if val end end out end |
.secure_compare(a, b) ⇒ Object
52 53 54 55 56 57 58 59 |
# File 'lib/open_wire/webhook.rb', line 52 def secure_compare(a, b) return false if a.bytesize != b.bytesize l = a.unpack("C*") r = 0 b.each_byte.with_index { |byte, i| r |= byte ^ l[i] } r.zero? end |
.verify_and_parse!(opts) ⇒ Object
opts:
secret: expected webhook secret (required unless allow_missing_secret)
body: raw request body string OR already-parsed Hash
headers: Hash-like (Rack env or ActionDispatch headers)
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/open_wire/webhook.rb', line 16 def verify_and_parse!(opts) secret = opts.fetch(:secret) body = opts.fetch(:body) headers = normalize_headers(opts[:headers] || {}) provided = headers[HEADER_SECRET.downcase] || headers[HEADER_SECRET] || "" raise AuthError, "Missing X-Open-Wire-Secret" if provided.to_s.empty? raise AuthError, "Invalid Open-Wire webhook secret" unless secure_compare(provided.to_s, secret.to_s) protocol = headers[HEADER_PROTOCOL.downcase] || headers[HEADER_PROTOCOL] if protocol && protocol.to_s != OpenWire::PROTOCOL raise WebhookError, "Unsupported protocol #{protocol}" end Envelope.parse_inbound(body) end |