# frozen_string_literal: true RSpec.describe StrikeMe::API::Webhook do let(:secret) { 'a-webhook-subscription-secret' } let(:raw_body) { '{"id":"245e40d8-f197-411c-8f20-a326d08da402","eventType":"invoice.updated","webhookVersion":"v1","data":{"entityId":"602cc206-6b4a-42dd-bc89-9a534bb04034","changes":["state"]},"created":"2026-09-15T12:00:00+00:00","deliverySuccess":true}' } let(:real_signature) { OpenSSL::HMAC.hexdigest('SHA256', secret, raw_body) } describe '.valid_signature?' do it 'is true for a signature computed with the same secret over the same raw body' do expect(described_class.valid_signature?(raw_body: raw_body, signature: real_signature, secret: secret)).to eq true end it 'is false for the wrong secret' do expect(described_class.valid_signature?(raw_body: raw_body, signature: real_signature, secret: 'wrong')).to eq false end it 'is false if the body was tampered with after signing' do tampered = raw_body.sub('"state"', '"amount"') expect(described_class.valid_signature?(raw_body: tampered, signature: real_signature, secret: secret)).to eq false end it 'is false for a blank signature, rather than raising' do expect(described_class.valid_signature?(raw_body: raw_body, signature: '', secret: secret)).to eq false expect(described_class.valid_signature?(raw_body: raw_body, signature: nil, secret: secret)).to eq false end it 'is false (not a raised length-mismatch error) for a garbled/truncated signature' do expect(described_class.valid_signature?(raw_body: raw_body, signature: 'not-a-real-length', secret: secret)).to eq false end end end