From 73bcf928e499f1ae8a902fe1b35c85046ffa49aa Mon Sep 17 00:00:00 2001 From: paulwer Date: Tue, 19 Mar 2024 12:56:39 +0100 Subject: [PATCH] updates mailgun webhook loading message data on runtime --- .../MailgunInboundWebhookTransformer.php | 47 ----------------- app/Http/Controllers/MailgunController.php | 11 ++-- .../Mailgun/ProcessMailgunInboundWebhook.php | 51 +++++++++++++++---- .../IngresEmail/IngresEmailEngine.php | 2 - 4 files changed, 48 insertions(+), 63 deletions(-) delete mode 100644 app/Helpers/IngresMail/Transformer/MailgunInboundWebhookTransformer.php diff --git a/app/Helpers/IngresMail/Transformer/MailgunInboundWebhookTransformer.php b/app/Helpers/IngresMail/Transformer/MailgunInboundWebhookTransformer.php deleted file mode 100644 index 45a261f18d3d..000000000000 --- a/app/Helpers/IngresMail/Transformer/MailgunInboundWebhookTransformer.php +++ /dev/null @@ -1,47 +0,0 @@ -from = $data["sender"]; // TODO: maybe a fallback have to be used to extract email from $data["From"] - $ingresEmail->to = $data["recipient"]; // TODO: maybe a fallback have to be used to extract email from $data["To"] - $ingresEmail->subject = $data["Subject"]; - $ingresEmail->body = $data["body-html"]; - $ingresEmail->text_body = $data["body-plain"]; - $ingresEmail->date = Carbon::createFromTimestamp((int) $data["timestamp"]); - - // parse documents as UploadedFile from webhook-data - foreach (json_decode($data["attachments"]) as $attachment) { - - // prepare url with credentials before downloading :: https://github.com/mailgun/mailgun.js/issues/24 - $url = $attachment->url; - $credentials = config('services.mailgun.domain') . ":" . config('services.mailgun.secret') . "@"; - $url = str_replace("http://", "http://" . $credentials, $url); - $url = str_replace("https://", "https://" . $credentials, $url); - - // download file and save to tmp dir - $ingresEmail->documents[] = TempFile::UploadedFileFromUrl($url, $attachment->name, $attachment->{"content-type"}); - - } - - return $ingresEmail; - } -} diff --git a/app/Http/Controllers/MailgunController.php b/app/Http/Controllers/MailgunController.php index 0d2e1c91e937..28a257d2e4e1 100644 --- a/app/Http/Controllers/MailgunController.php +++ b/app/Http/Controllers/MailgunController.php @@ -115,19 +115,24 @@ class MailgunController extends BaseController { $input = $request->all(); + if (!array_key_exists('recipient', $input) || !array_key_exists('message-url', $input)) { + Log::info('Failed: Message could not be parsed, because required parameters are missing. Please ensure contacting this api-endpoint with a store & notify operation instead of a forward operation!'); + return response()->json(['message' => 'Failed. Missing Parameters'], 400); + } + if (!array_key_exists('attachments', $input) || count(json_decode($input['attachments'])) == 0) { - Log::info('Message ignored because of missing attachments. Please ensure contacting this api-endpoint with a store & notify operation instead of a forward operation'); + Log::info('Message ignored because of missing attachments. No Actions would have been taken...'); return response()->json(['message' => 'Sucess. Soft Fail. Missing Attachments.'], 200); } - if (\abs(\time() - (int) $request['timestamp']) > 150) { + if (\abs(\time() - (int) $input['timestamp']) > 150) { Log::info('Message ignored because of request body is too old.'); return response()->json(['message' => 'Success. Soft Fail. Message too old.'], 200); } // @turbo124 TODO: how to check for services.mailgun.webhook_signing_key on company level, when custom credentials are defined if (\hash_equals(\hash_hmac('sha256', $input['timestamp'] . $input['token'], config('services.mailgun.webhook_signing_key')), $input['signature'])) { - ProcessMailgunInboundWebhook::dispatch($input)->delay(10); + ProcessMailgunInboundWebhook::dispatch($input["recipient"] . "|" . $input["message-url"])->delay(10); return response()->json(['message' => 'Success'], 201); } diff --git a/app/Jobs/Mailgun/ProcessMailgunInboundWebhook.php b/app/Jobs/Mailgun/ProcessMailgunInboundWebhook.php index b8a9ffc578d2..d616598167e3 100644 --- a/app/Jobs/Mailgun/ProcessMailgunInboundWebhook.php +++ b/app/Jobs/Mailgun/ProcessMailgunInboundWebhook.php @@ -11,9 +11,11 @@ namespace App\Jobs\Mailgun; -use App\Helpers\IngresMail\Transformer\MailgunInboundWebhookTransformer; use App\Libraries\MultiDB; +use App\Services\IngresEmail\IngresEmail; use App\Services\IngresEmail\IngresEmailEngine; +use App\Utils\TempFile; +use Illuminate\Support\Carbon; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; @@ -29,9 +31,9 @@ class ProcessMailgunInboundWebhook implements ShouldQueue /** * Create a new job instance. - * + * $input consists of 2 informations: recipient|messageUrl */ - public function __construct(private array $request) + public function __construct(private string $input) { } @@ -43,21 +45,48 @@ class ProcessMailgunInboundWebhook implements ShouldQueue */ public function handle() { - if (!array_key_exists('To', $this->request) || !array_key_exists('attachments', $this->request) || !array_key_exists('timestamp', $this->request) || !array_key_exists('Subject', $this->request) || !(array_key_exists('body-html', $this->request) || array_key_exists('body-plain', $this->request))) - throw new \Exception('invalid body'); + $recipient = explode("|", $this->input)[0]; // match company - $company = MultiDB::findAndSetDbByExpenseMailbox($this->request["To"]); + $company = MultiDB::findAndSetDbByExpenseMailbox($recipient); if (!$company) { - Log::info('unknown Expense Mailbox occured while handling an inbound email from mailgun: ' . $this->request["To"]); + Log::info('unknown Expense Mailbox occured while handling an inbound email from mailgun: ' . $recipient); return; } - // prepare - $ingresMail = (new MailgunInboundWebhookTransformer())->transform($this->request); - Log::info(json_encode($ingresMail)); + // fetch message from mailgun-api + $mailgun_domain = $company->settings?->email_sending_method === 'client_mailgun' && $company->settings?->mailgun_domain ? $company->settings?->mailgun_domain : config('services.mailgun.domain'); + $mailgun_secret = $company->settings?->email_sending_method === 'client_mailgun' && $company->settings?->mailgun_secret ? $company->settings?->mailgun_secret : config('services.mailgun.secret'); + $credentials = $mailgun_domain . ":" . $mailgun_secret . "@"; + $messageUrl = explode("|", $this->input)[1]; + $messageUrl = str_replace("http://", "http://" . $credentials, $messageUrl); + $messageUrl = str_replace("https://", "https://" . $credentials, $messageUrl); + $mail = json_decode(file_get_contents($messageUrl)); + + // prepare data for ingresEngine + $ingresEmail = new IngresEmail(); + + $ingresEmail->from = $mail->sender; + $ingresEmail->to = $recipient; // usage of data-input, because we need a single email here + $ingresEmail->subject = $mail->Subject; + $ingresEmail->body = $mail->{"body-html"}; + $ingresEmail->text_body = $mail->{"body-plain"}; + $ingresEmail->date = Carbon::createFromTimeString($mail->Date); + + // parse documents as UploadedFile from webhook-data + foreach ($mail->attachments as $attachment) { + + // prepare url with credentials before downloading :: https://github.com/mailgun/mailgun.js/issues/24 + $url = $attachment->url; + $url = str_replace("http://", "http://" . $credentials, $url); + $url = str_replace("https://", "https://" . $credentials, $url); + + // download file and save to tmp dir + $ingresEmail->documents[] = TempFile::UploadedFileFromUrl($url, $attachment->name, $attachment->{"content-type"}); + + } // perform - (new IngresEmailEngine($ingresMail))->handle(); + (new IngresEmailEngine($ingresEmail))->handle(); } } diff --git a/app/Services/IngresEmail/IngresEmailEngine.php b/app/Services/IngresEmail/IngresEmailEngine.php index 42fd8a304719..bb03f9d5cce8 100644 --- a/app/Services/IngresEmail/IngresEmailEngine.php +++ b/app/Services/IngresEmail/IngresEmailEngine.php @@ -182,8 +182,6 @@ class IngresEmailEngine $expense->saveQuietly(); - Log::info(json_encode($documents)); - $this->saveDocuments($documents, $expense); event(new ExpenseWasCreated($expense, $expense->company, Ninja::eventVars(null))); // @turbo124 please check, I copied from API-Controller