From 7665700b005bfea38de47043b182651f228d0b4f Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Sat, 8 Apr 2017 01:29:20 +0200 Subject: [PATCH] Implemented a way to verify webhook signature (#325) * Implemented a way to verify webhook signature * CS --- src/Mailgun/Api/Webhook.php | 48 ++++++++++++++++++++++++++ src/Mailgun/HttpClientConfigurator.php | 2 +- src/Mailgun/Mailgun.php | 10 +++--- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/Mailgun/Api/Webhook.php b/src/Mailgun/Api/Webhook.php index 5b262f2..0dd1f18 100644 --- a/src/Mailgun/Api/Webhook.php +++ b/src/Mailgun/Api/Webhook.php @@ -9,18 +9,66 @@ namespace Mailgun\Api; +use Http\Client\HttpClient; use Mailgun\Assert; +use Mailgun\Hydrator\Hydrator; use Mailgun\Model\Webhook\CreateResponse; use Mailgun\Model\Webhook\DeleteResponse; use Mailgun\Model\Webhook\IndexResponse; use Mailgun\Model\Webhook\ShowResponse; use Mailgun\Model\Webhook\UpdateResponse; +use Mailgun\RequestBuilder; /** * @author Tobias Nyholm */ class Webhook extends HttpApi { + /** + * @var string + */ + private $apiKey; + + /** + * @param HttpClient $httpClient + * @param RequestBuilder $requestBuilder + * @param Hydrator $hydrator + * @param string $apiKey + */ + public function __construct(HttpClient $httpClient, RequestBuilder $requestBuilder, Hydrator $hydrator, $apiKey) + { + parent::__construct($httpClient, $requestBuilder, $hydrator); + $this->apiKey = $apiKey; + } + + /** + * This function verifies the webhook signature with your API key to to see if it is authentic. + * + * If this function returns FALSE, you must not process the request. + * You should reject the request with status code 403 Forbidden. + * + * @param int $timestamp + * @param string $token + * @param string $signature + * + * @return bool + */ + public function verifyWebhookSignature($timestamp, $token, $signature) + { + if (empty($timestamp) || empty($token) || empty($signature)) { + return false; + } + + $hmac = hash_hmac('sha256', $timestamp.$token, $this->apiKey); + + if (function_exists('hash_equals')) { + // hash_equals is constant time, but will not be introduced until PHP 5.6 + return hash_equals($hmac, $signature); + } else { + return $hmac === $signature; + } + } + /** * @param string $domain * diff --git a/src/Mailgun/HttpClientConfigurator.php b/src/Mailgun/HttpClientConfigurator.php index 0313163..d156738 100644 --- a/src/Mailgun/HttpClientConfigurator.php +++ b/src/Mailgun/HttpClientConfigurator.php @@ -110,7 +110,7 @@ final class HttpClientConfigurator /** * @return string */ - private function getApiKey() + public function getApiKey() { return $this->apiKey; } diff --git a/src/Mailgun/Mailgun.php b/src/Mailgun/Mailgun.php index 98e6552..c8d25c8 100644 --- a/src/Mailgun/Mailgun.php +++ b/src/Mailgun/Mailgun.php @@ -84,20 +84,20 @@ class Mailgun } /** - * @param HttpClientConfigurator $httpClientConfigurator + * @param HttpClientConfigurator $configurator * @param Hydrator|null $hydrator * @param RequestBuilder|null $requestBuilder * * @return Mailgun */ public static function configure( - HttpClientConfigurator $httpClientConfigurator, + HttpClientConfigurator $configurator, Hydrator $hydrator = null, RequestBuilder $requestBuilder = null ) { - $httpClient = $httpClientConfigurator->createConfiguredClient(); + $httpClient = $configurator->createConfiguredClient(); - return new self(null, $httpClient, 'api.mailgun.net', $hydrator, $requestBuilder); + return new self($configurator->getApiKey(), $httpClient, 'api.mailgun.net', $hydrator, $requestBuilder); } /** @@ -358,7 +358,7 @@ class Mailgun */ public function webhooks() { - return new Api\Webhook($this->httpClient, $this->requestBuilder, $this->hydrator); + return new Api\Webhook($this->httpClient, $this->requestBuilder, $this->hydrator, $this->apiKey); } /**