From 12fddb811bbb94ba22d413964a61376b77e1b675 Mon Sep 17 00:00:00 2001 From: joelharkes Date: Fri, 24 Mar 2023 18:20:09 +0100 Subject: [PATCH 1/3] Add mailcare support for raw emails over http --- src/Http/Requests/MailCareRequest.php | 20 ++++++++-- tests/Controllers/MailCareTest.php | 57 +++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 tests/Controllers/MailCareTest.php diff --git a/src/Http/Requests/MailCareRequest.php b/src/Http/Requests/MailCareRequest.php index fd4405b..eafcc3a 100644 --- a/src/Http/Requests/MailCareRequest.php +++ b/src/Http/Requests/MailCareRequest.php @@ -10,13 +10,25 @@ class MailCareRequest extends FormRequest { public function validator() { - return Validator::make($this->all(), [ - 'email' => 'required', - ]); + return Validator::make([], []); } public function email() { - return InboundEmail::fromMessage($this->get('email')); + return InboundEmail::fromMessage($this->getRawRequest()); + } + + protected function getRawRequest(): string + { + $rawBodyFromApache = file_get_contents('php://input'); + $headersFromApache = getallheaders(); + if($rawBodyFromApache && $headersFromApache !== false && count($headersFromApache)> 0){ + $rawHeader = ""; + foreach($headersFromApache as $key => $value){ + $rawHeader .= "{$key}: {$value}\r\n"; + } + return "{$rawHeader}\r\n{$rawBodyFromApache}"; + } + return $this->__toString(); } } diff --git a/tests/Controllers/MailCareTest.php b/tests/Controllers/MailCareTest.php new file mode 100644 index 0000000..ed5f999 --- /dev/null +++ b/tests/Controllers/MailCareTest.php @@ -0,0 +1,57 @@ +subject("subject"); + $message->from("from@example.com"); + $message->to("to@example.com"); + $message->text("this is body text"); + + Mailbox::shouldReceive("callMailboxes", function(InboundEmail $email){ + return $email->subject() === 'this is body text' + && $email->from() === 'from@example.com' + && $email->to()[0]->getEmail() === 'to@example.com' + && $email->body() === 'this is body text'; + }); + $this->callWithEmail('POST','/laravel-mailbox/mailcare',$message) + ->assertStatus(200); + } + + private function callWithEmail(string $method, string $url, Email $message): \Illuminate\Testing\TestResponse + { + $raw = $message->toString(); + $parts = explode("\r\n\r\n", $raw); + $headerRaw = array_shift($parts); + $bodyRaw = implode("\r\n\r\n", $parts); + $headers = []; + foreach(explode("\r\n", $headerRaw) as $headerRawLine){ + list($name, $value) = explode(': ',$headerRawLine); + $headers[$name] = $value; + } + $server = $this->transformHeadersToServerVars($headers); + return $this->call($method, $url,[],[],[], $server, $bodyRaw); + } +} From a0026f7b614cc9b161eca13b0c5e3aff799be1f7 Mon Sep 17 00:00:00 2001 From: joelharkes Date: Fri, 24 Mar 2023 18:36:07 +0100 Subject: [PATCH 2/3] Mailcare add content-type check --- src/Http/Requests/MailCareRequest.php | 25 ++++++++++--------------- tests/Controllers/MailCareTest.php | 15 ++++----------- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/Http/Requests/MailCareRequest.php b/src/Http/Requests/MailCareRequest.php index eafcc3a..313e93a 100644 --- a/src/Http/Requests/MailCareRequest.php +++ b/src/Http/Requests/MailCareRequest.php @@ -8,27 +8,22 @@ class MailCareRequest extends FormRequest { - public function validator() + public function rules() { - return Validator::make([], []); + return [ + "content_type" => "required|in:message/rfc2822", + ]; } - public function email() + public function prepareForValidation() { - return InboundEmail::fromMessage($this->getRawRequest()); + $this->merge([ + "content_type" => $this->headers->get("Content-type"), + ]); } - protected function getRawRequest(): string + public function email() { - $rawBodyFromApache = file_get_contents('php://input'); - $headersFromApache = getallheaders(); - if($rawBodyFromApache && $headersFromApache !== false && count($headersFromApache)> 0){ - $rawHeader = ""; - foreach($headersFromApache as $key => $value){ - $rawHeader .= "{$key}: {$value}\r\n"; - } - return "{$rawHeader}\r\n{$rawBodyFromApache}"; - } - return $this->__toString(); + return InboundEmail::fromMessage($this->getContent()); } } diff --git a/tests/Controllers/MailCareTest.php b/tests/Controllers/MailCareTest.php index ed5f999..30f77b3 100644 --- a/tests/Controllers/MailCareTest.php +++ b/tests/Controllers/MailCareTest.php @@ -42,16 +42,9 @@ public function it_accepts_raw_email_requests(): void private function callWithEmail(string $method, string $url, Email $message): \Illuminate\Testing\TestResponse { - $raw = $message->toString(); - $parts = explode("\r\n\r\n", $raw); - $headerRaw = array_shift($parts); - $bodyRaw = implode("\r\n\r\n", $parts); - $headers = []; - foreach(explode("\r\n", $headerRaw) as $headerRawLine){ - list($name, $value) = explode(': ',$headerRawLine); - $headers[$name] = $value; - } - $server = $this->transformHeadersToServerVars($headers); - return $this->call($method, $url,[],[],[], $server, $bodyRaw); + $server = $this->transformHeadersToServerVars([ + "Content-Type" => 'message/rfc2822' + ]); + return $this->call($method, $url,[],[],[], $server, $message->toString()); } } From a55122d777799305b592f02f55bdb770a3262b4e Mon Sep 17 00:00:00 2001 From: joelharkes Date: Fri, 24 Mar 2023 18:44:23 +0100 Subject: [PATCH 3/3] Also add complete test to mailgun --- tests/Controllers/MailCareTest.php | 3 +- tests/Controllers/MailgunTest.php | 52 +++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/tests/Controllers/MailCareTest.php b/tests/Controllers/MailCareTest.php index 30f77b3..62b3f70 100644 --- a/tests/Controllers/MailCareTest.php +++ b/tests/Controllers/MailCareTest.php @@ -6,6 +6,7 @@ use BeyondCode\Mailbox\Facades\Mailbox; use BeyondCode\Mailbox\InboundEmail; use BeyondCode\Mailbox\Tests\TestCase; +use Illuminate\Testing\TestResponse; use Symfony\Component\Mime\Email; class MailCareTest extends TestCase @@ -40,7 +41,7 @@ public function it_accepts_raw_email_requests(): void ->assertStatus(200); } - private function callWithEmail(string $method, string $url, Email $message): \Illuminate\Testing\TestResponse + private function callWithEmail(string $method, string $url, Email $message): TestResponse { $server = $this->transformHeadersToServerVars([ "Content-Type" => 'message/rfc2822' diff --git a/tests/Controllers/MailgunTest.php b/tests/Controllers/MailgunTest.php index af10733..d3490d6 100644 --- a/tests/Controllers/MailgunTest.php +++ b/tests/Controllers/MailgunTest.php @@ -2,7 +2,11 @@ namespace BeyondCode\Mailbox\Tests\Controllers; +use BeyondCode\Mailbox\Facades\Mailbox; +use BeyondCode\Mailbox\InboundEmail; use BeyondCode\Mailbox\Tests\TestCase; +use Illuminate\Testing\TestResponse; +use Symfony\Component\Mime\Email; class MailgunTest extends TestCase { @@ -23,7 +27,15 @@ public function it_verifies_mailgun_signatures() 'signature' => 'something', ])->assertStatus(401); - $timestamp = time(); + + $this->callWithValidToken('mime') + ->assertStatus(200); + } + + /** @test */ + public function it_verifies_fresh_timestamps() + { + $timestamp = now()->subMinutes(5)->timestamp; $token = uniqid(); $this->app['config']['mailbox.services.mailgun.key'] = '12345'; @@ -35,24 +47,48 @@ public function it_verifies_mailgun_signatures() 'timestamp' => $timestamp, 'token' => $token, 'signature' => $validSignature, - ])->assertStatus(200); + ])->assertStatus(401); } - /** @test */ - public function it_verifies_fresh_timestamps() + + /** + * @test + */ + public function it_processes_mails_correctly() { - $timestamp = now()->subMinutes(5)->timestamp; + $message = new Email(); + $message->subject("subject"); + $message->from("from@example.com"); + $message->to("to@example.com"); + $message->text("this is body text"); + + Mailbox::shouldReceive("callMailboxes", function(InboundEmail $email){ + return $email->subject() === 'this is body text' + && $email->from() === 'from@example.com' + && $email->to()[0]->getEmail() === 'to@example.com' + && $email->body() === 'this is body text'; + }); + + $this->callWithValidToken($message->toString()) + ->assertStatus(200); + } + + + private function callWithValidToken($mimeMail = 'mime'): TestResponse + { + $timestamp = time(); $token = uniqid(); $this->app['config']['mailbox.services.mailgun.key'] = '12345'; $validSignature = hash_hmac('sha256', $timestamp.$token, '12345'); - $this->post('/laravel-mailbox/mailgun/mime', [ - 'body-mime' => 'mime', + return $this->post('/laravel-mailbox/mailgun/mime', [ + 'body-mime' => $mimeMail, 'timestamp' => $timestamp, 'token' => $token, 'signature' => $validSignature, - ])->assertStatus(401); + ]); } + }