From 9ae908e4405fa7326290a8757e511ef30f88503b Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Sun, 15 Sep 2024 13:17:18 -0400 Subject: [PATCH] [Mailer] enable Sendgrid to parse multiple events --- .../Tests/Webhook/Fixtures/batch.json | 4 +++ .../Sendgrid/Tests/Webhook/Fixtures/batch.php | 19 ++++++++++++ .../Tests/Webhook/Fixtures/webhook.php | 2 +- .../SendgridSignedRequestParserTest.php | 29 +++++++++++++++++-- .../Webhook/SendgridRequestParser.php | 7 +++-- .../Mailer/Bridge/Sendgrid/composer.json | 5 ++-- 6 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/batch.json create mode 100644 src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/batch.php diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/batch.json b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/batch.json new file mode 100644 index 0000000000000..dc6f98bf9c200 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/batch.json @@ -0,0 +1,4 @@ +[ + {"email":"hello@world.com","event":"dropped","reason":"Bounced Address","sg_event_id":"ZHJvcC0xMDk5NDkxOS1MUnpYbF9OSFN0T0doUTRrb2ZTbV9BLTA","sg_message_id":"LRzXl_NHStOGhQ4kofSm_A.filterdrecv-p3mdw1-756b745b58-kmzbl-18-5F5FC76C-9.0","smtp-id":"","timestamp":1600112492}, + {"email":"hello@world.com","event":"click","sg_event_id":"ZHJvcC0xMDk5NDkxOS1MUnpYbF9OSFN0T0doUTRrb2ZTbV9BLTA","sg_message_id":"LRzXl_NHStOGhQ4kofSm_A.filterdrecv-p3mdw1-756b745b58-kmzbl-18-5F5FC76C-9.0","smtp-id":"","timestamp":1600112492} +] diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/batch.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/batch.php new file mode 100644 index 0000000000000..f7af505fb5c9f --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/batch.php @@ -0,0 +1,19 @@ +setRecipientEmail('hello@world.com'); +$wh1->setTags([]); +$wh1->setMetadata([]); +$wh1->setReason('Bounced Address'); +$wh1->setDate(\DateTimeImmutable::createFromFormat('U', 1600112492)); + +$wh2 = new MailerEngagementEvent(MailerEngagementEvent::CLICK, 'LRzXl_NHStOGhQ4kofSm_A.filterdrecv-p3mdw1-756b745b58-kmzbl-18-5F5FC76C-9.0', json_decode(file_get_contents(str_replace('.php', '.json', __FILE__)), true)[1]); +$wh2->setRecipientEmail('hello@world.com'); +$wh2->setTags([]); +$wh2->setMetadata([]); +$wh2->setDate(\DateTimeImmutable::createFromFormat('U', 1600112492)); + +return [$wh1, $wh2]; diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/webhook.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/webhook.php index e762c87a853f8..f7aac030ac72e 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/webhook.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/Fixtures/webhook.php @@ -9,4 +9,4 @@ $wh->setReason('Bounced Address'); $wh->setDate(\DateTimeImmutable::createFromFormat('U', 1600112492)); -return $wh; +return [$wh]; diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/SendgridSignedRequestParserTest.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/SendgridSignedRequestParserTest.php index bc4ed7cd5b28b..b39c8ffb8c131 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/SendgridSignedRequestParserTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Webhook/SendgridSignedRequestParserTest.php @@ -24,6 +24,25 @@ */ class SendgridSignedRequestParserTest extends AbstractRequestParserTestCase { + private const PRIVATE_KEY = <<<'KEY' + -----BEGIN RSA PRIVATE KEY----- + MIICWgIBAAKBgHH/ZmiTGDi6/1IIx4vOKedN24Zuxj9G0ioNpCbNssQlukWijQiz + UaOZ98JgEA11jGY1gFwCKYVSH5e1ZWN+m4hdxNQoNn8QaODzyo2ocGbobzrIuMJp + mroyl6WmNa0jW8DMoW1Mpsxo/Vw9FrkAL+eSYgR8ZFWeXbcD8yRfVm/lAgMBAAEC + gYBDqSUtWHD96u9zz0Yw0pLIeMudBM6h6/T9hM8zQM+j4AipIAu5aEVCZzZIph+g + /W3xlDu1YIsoWE/sCXw+C31gLgDAd/4++G+3nuQumv5TgdWyZkXrFZ+HiPk77fqh + F6U+5vTSYS/BOueisDUY7ndgf9pFVZtj5rKHHOmL26KFgQJBAK6npY3H1UyYHi/t + vaxH/5KVqBDWuUE1+MjyVF0KbjyZOzMka7/4DenbBsZRDCqNrP8psuCwOFPf+vwN + uVmE7vECQQCnF4F/INbeZkL3EQTMhCF3kIuY9jtB/ah+FQ/zom0gcw4zNAzKVeFm + SmCTAeZbqq+fTFgwueIE4mPv4hiT0Hg1AkBIqoGr6p+pPYUZxd1rh40i7Nc/Ikdz + hUQcPw6woz1YQxypW5blCQyo5rL74g6gyc9XXn8JEuhspTzkj8U1JKTRAkASdDAj + IDda3KRssP58r+MaV2ZzgE5PHXqsYhse50NyIALjeM4o0o9QQsqjscQFP7ahu0bK + Kt1heLdc2PWp7Y45AkAdAVZd//vS9FLU397DZAf7h+5qhUmPkm8vxnehCH+olQXq + SPExlMI7PVpISz7jk9hRF31NStTZok//CUcq+yxJ + -----END RSA PRIVATE KEY----- + KEY; + private const SECRET = 'MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHH/ZmiTGDi6/1IIx4vOKedN24Zuxj9G0ioNpCbNssQlukWijQizUaOZ98JgEA11jGY1gFwCKYVSH5e1ZWN+m4hdxNQoNn8QaODzyo2ocGbobzrIuMJpmroyl6WmNa0jW8DMoW1Mpsxo/Vw9FrkAL+eSYgR8ZFWeXbcD8yRfVm/lAgMBAAE='; + protected function createRequestParser(): RequestParserInterface { return new SendgridRequestParser(new SendgridPayloadConverter(), true); @@ -34,15 +53,19 @@ protected function createRequestParser(): RequestParserInterface */ protected function createRequest(string $payload): Request { + $payload = str_replace("\n", "\r\n", $payload); + + openssl_sign('1600112502'.$payload, $signature, self::PRIVATE_KEY, \OPENSSL_ALGO_SHA256); + return Request::create('/', 'POST', [], [], [], [ 'Content-Type' => 'application/json', - 'HTTP_X-Twilio-Email-Event-Webhook-Signature' => 'MEUCIGHQVtGj+Y3LkG9fLcxf3qfI10QysgDWmMOVmxG0u6ZUAiEAyBiXDWzM+uOe5W0JuG+luQAbPIqHh89M15TluLtEZtM=', + 'HTTP_X-Twilio-Email-Event-Webhook-Signature' => base64_encode($signature), 'HTTP_X-Twilio-Email-Event-Webhook-Timestamp' => '1600112502', - ], str_replace("\n", "\r\n", $payload)); + ], $payload); } protected function getSecret(): string { - return 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE83T4O/n84iotIvIW4mdBgQ/7dAfSmpqIM8kF9mN1flpVKS3GRqe62gw+2fNNRaINXvVpiglSI8eNEc6wEA3F+g=='; + return self::SECRET; } } diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Webhook/SendgridRequestParser.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Webhook/SendgridRequestParser.php index b0f7f78dc4948..26bea852dc81d 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Webhook/SendgridRequestParser.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Webhook/SendgridRequestParser.php @@ -41,7 +41,10 @@ protected function getRequestMatcher(): RequestMatcherInterface ]); } - protected function doParse(Request $request, string $secret): ?AbstractMailerEvent + /** + * @return AbstractMailerEvent[] + */ + protected function doParse(Request $request, string $secret): array { $content = $request->toArray(); if ( @@ -69,7 +72,7 @@ protected function doParse(Request $request, string $secret): ?AbstractMailerEve } try { - return $this->converter->convert($content[0]); + return array_map($this->converter->convert(...), $content); } catch (ParseException $e) { throw new RejectWebhookException(406, $e->getMessage(), $e); } diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/composer.json b/src/Symfony/Component/Mailer/Bridge/Sendgrid/composer.json index f8982a448063f..26d2195e42ce6 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/composer.json +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/composer.json @@ -21,11 +21,12 @@ }, "require-dev": { "symfony/http-client": "^6.4|^7.0", - "symfony/webhook": "^6.4|^7.0" + "symfony/webhook": "^7.2" }, "conflict": { "symfony/mime": "<6.4", - "symfony/http-foundation": "<6.4" + "symfony/http-foundation": "<6.4", + "symfony/webhook": "<7.2" }, "autoload": { "psr-4": { "Symfony\\Component\\Mailer\\Bridge\\Sendgrid\\": "" },