class Attio::Util::WebhookSignature::Handler

Helper class for webhook handlers

def extract_body(request)

def extract_body(request)
  case request
  when Hash
    request[:body] || request["body"] || ""
  when defined?(Rack::Request) && Rack::Request
    request.body.rewind
    request.body.read
  when defined?(ActionDispatch::Request) && ActionDispatch::Request
    request.raw_post
  else
    raise ArgumentError, "Unsupported request type: #{request.class}"
  end
end

def extract_headers(request)

def extract_headers(request)
  case request
  when Hash
    request[:headers] || request["headers"] || {}
  when defined?(Rack::Request) && Rack::Request
    request.env.select { |k, _| k.start_with?("HTTP_") }.transform_keys { |k| k.sub(/^HTTP_/, "").downcase }
  when defined?(ActionDispatch::Request) && ActionDispatch::Request
    request.headers.to_h
  else
    raise ArgumentError, "Unsupported request type: #{request.class}"
  end
end

def initialize(secret)

def initialize(secret)
  @secret = secret
  validate_secret!
end

def parse_and_verify(request)

Parse and verify a request
def parse_and_verify(request)
  verify_request(request)
  body = extract_body(request)
  JSON.parse(body, symbolize_names: true)
rescue JSON::ParserError => e
  raise SignatureVerificationError, "Invalid JSON payload: #{e.message}"
end

def validate_secret!

def validate_secret!
  raise ArgumentError, "Webhook secret is required" if secret.nil? || secret.empty?
end

def verify_request(request)

Verify a request
def verify_request(request)
  headers = extract_headers(request)
  body = extract_body(request)
  signature_data = WebhookSignature.extract_from_headers(headers)
  WebhookSignature.verify!(
    payload: body,
    signature: signature_data[:signature],
    timestamp: signature_data[:timestamp],
    secret: secret
  )
end