Class: SignalWire::Security::WebhookMiddleware
- Inherits:
-
Object
- Object
- SignalWire::Security::WebhookMiddleware
- Defined in:
- lib/signalwire/security/webhook_middleware.rb
Overview
Rack middleware that rejects webhook requests with bad signatures.
Configure with the customer’s Signing Key (and optional “trust_proxy“ to honor X-Forwarded headers). Mount upstream of any body-parsing middleware so the raw bytes survive intact.
Constant Summary collapse
- SIGNALWIRE_SIGNATURE_HEADER =
'HTTP_X_SIGNALWIRE_SIGNATURE'- TWILIO_COMPAT_SIGNATURE_HEADER =
'HTTP_X_TWILIO_SIGNATURE'- RAW_BODY_ENV_KEY =
Key under which the captured raw body is stashed on the request env.
'signalwire.raw_body'
Instance Method Summary collapse
- #call(env) ⇒ Object private
-
#initialize(app, signing_key:, trust_proxy: false, paths: nil, methods: ['POST']) ⇒ WebhookMiddleware
constructor
A new instance of WebhookMiddleware.
Constructor Details
#initialize(app, signing_key:, trust_proxy: false, paths: nil, methods: ['POST']) ⇒ WebhookMiddleware
Returns a new instance of WebhookMiddleware.
66 67 68 69 70 71 72 73 74 |
# File 'lib/signalwire/security/webhook_middleware.rb', line 66 def initialize(app, signing_key:, trust_proxy: false, paths: nil, methods: ['POST']) raise ArgumentError, 'signing_key is required' if signing_key.nil? || signing_key.to_s.empty? @app = app @signing_key = signing_key @trust_proxy = trust_proxy @paths = paths.nil? ? nil : Array(paths).map(&:to_s) @methods = methods.nil? ? nil : Array(methods).map { |m| m.to_s.upcase } end |
Instance Method Details
#call(env) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/signalwire/security/webhook_middleware.rb', line 77 def call(env) return @app.call(env) unless _applies?(env) # Capture raw body BEFORE any other middleware reads the stream. raw_body = _read_raw_body(env) env[RAW_BODY_ENV_KEY] = raw_body signature = _extract_signature_header(env) return _forbidden if signature.nil? || signature.empty? url = _reconstruct_url(env) valid = begin WebhookValidator.validate_webhook_signature(@signing_key, signature, url, raw_body) rescue ArgumentError, TypeError # Programming errors at the boundary — never leak which branch # tripped. Reject the request without raising. return _forbidden end return _forbidden unless valid @app.call(env) end |