diff --git a/src/Exceptions/WebhookFailed.php b/src/Exceptions/WebhookFailed.php index 6b95858..b6034dc 100644 --- a/src/Exceptions/WebhookFailed.php +++ b/src/Exceptions/WebhookFailed.php @@ -7,6 +7,11 @@ class WebhookFailed extends Exception { + public static function invalidSignature(): self + { + return new static('The signature is invalid.'); + } + public static function signingSecretNotSet(): self { return new static('The webhook signing secret is not set. Make sure that the `signing_secret` config key is set to the correct value.'); diff --git a/src/Webhook.php b/src/Webhook.php index feed5bc..a1df910 100644 --- a/src/Webhook.php +++ b/src/Webhook.php @@ -2,20 +2,26 @@ namespace BinaryCats\MailgunWebhooks; +use BinaryCats\MailgunWebhooks\Exceptions\WebhookFailed; + class Webhook { /** * Validate and raise an appropriate event. * * @param $payload - * @param array $signature - * @param string $secret + * @param array $signature + * @param string $secret * @return BinaryCats\MailgunWebhooks\Event + * @throws WebhookFailed */ public static function constructEvent(array $payload, array $signature, string $secret): Event { // verify we are good, else throw an expection - WebhookSignature::make($signature, $secret)->verify(); + if (!WebhookSignature::make($signature, $secret)->verify()) { + throw WebhookFailed::invalidSignature(); + } + // Make an event return Event::constructFrom($payload); } diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index a884477..af6b018 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -159,10 +159,38 @@ public function a_request_with_a_config_key_will_use_the_correct_signing_secret( ], ]; - Arr::set($payload, 'signature', $this->determineMailgunSignature($payload)); + Arr::set($payload, 'signature', $this->determineMailgunSignature($payload, 'somekey')); $this ->postJson('mailgun-webhooks/somekey', $payload) ->assertSuccessful(); } + + + /** @test */ + public function an_invalid_signature_value_generates_a_500_error() + { + $payload = [ + 'event-data' => [ + 'event' => 'my.type', + 'key' => 'value', + ], + ]; + + Arr::set($payload, 'signature', [ + 'timestamp' => time(), + 'token' => 'some token', + 'signature' => 'invalid_signature' + ]); + + $this + ->postJson('mailgun-webhooks', $payload) + ->assertStatus(500); + + $this->assertCount(0, WebhookCall::get()); + + Event::assertNotDispatched('mailgun-webhooks::my.type'); + + $this->assertNull(cache('dummyjob')); + } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 624ccbe..a3fcec0 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -87,7 +87,7 @@ protected function determineMailgunSignature(array $payload, string $configKey = return [ 'timestamp' => $timestamp, 'token' => $token, - 'signature' => hash_hmac('sha256', "{$timestamp}.{$token}", $secret), + 'signature' => hash_hmac('sha256', "{$timestamp}{$token}", $secret), ]; } }