Class: Vortex::Webhooks

Inherits:
Object
  • Object
show all
Defined in:
lib/vortex/webhooks.rb

Overview

Core webhook verification and parsing.

This class is framework-agnostic — use it directly or with the Rails/Sinatra framework integrations.

Examples:

webhooks = Vortex::Webhooks.new(secret: ENV['VORTEX_WEBHOOK_SECRET'])
event = webhooks.construct_event(request.body.read, request.env['HTTP_X_VORTEX_SIGNATURE'])

Instance Method Summary collapse

Constructor Details

#initialize(secret:) ⇒ Webhooks

Returns a new instance of Webhooks.

Raises:

Parameters:

  • The webhook signing secret from your Vortex dashboard



24
25
26
27
28
# File 'lib/vortex/webhooks.rb', line 24

def initialize(secret:)
  raise ArgumentError, 'Vortex::Webhooks requires a secret' if secret.nil? || secret.empty?

  @secret = secret
end

Instance Method Details

#construct_event(payload, signature) ⇒ WebhookEvent, AnalyticsEvent

Verify and parse an incoming webhook payload.

Raises:

  • If the signature is invalid

Parameters:

  • The raw request body

  • The value of the X-Vortex-Signature header

Returns:

  • A typed event object



50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/vortex/webhooks.rb', line 50

def construct_event(payload, signature)
  raise WebhookSignatureError unless verify_signature(payload, signature)

  parsed = JSON.parse(payload)

  if Vortex.webhook_event?(parsed)
    WebhookEvent.new(parsed)
  elsif Vortex.analytics_event?(parsed)
    AnalyticsEvent.new(parsed)
  else
    WebhookEvent.new(parsed)
  end
end

#verify_signature(payload, signature) ⇒ Boolean

Verify the HMAC-SHA256 signature of an incoming webhook payload.

Parameters:

  • The raw request body

  • The value of the X-Vortex-Signature header

Returns:

  • true if the signature is valid



35
36
37
38
39
40
41
42
# File 'lib/vortex/webhooks.rb', line 35

def verify_signature(payload, signature)
  return false if signature.nil? || signature.empty?

  expected = OpenSSL::HMAC.hexdigest('SHA256', @secret, payload)

  # Timing-safe comparison to prevent timing attacks
  secure_compare(signature, expected)
end