Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
markvaneijk committed Sep 6, 2024
1 parent 0102f9c commit b20ca3b
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/Contracts/MailDriverContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ interface MailDriverContract
{
public function registerWebhooks($components): void;

public function verifyWebhookSignature(array $payload): bool;

public function getUuidFromPayload(array $payload): ?string;

public function getMailFromPayload(array $payload): ?Mail;
Expand Down
5 changes: 5 additions & 0 deletions src/Controllers/WebhookController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Http\Response;
use Vormkracht10\Mails\Enums\Provider;
use Vormkracht10\Mails\Events\MailEvent;
use Vormkracht10\Mails\Facades\MailProvider;

class WebhookController
{
Expand All @@ -15,6 +16,10 @@ public function __invoke(Request $request, string $driver): Response
return response('Unknown provider.', status: 400);
}

if (MailProvider::with($driver)->verifyWebhookSignature($request->all())) {
return response('Invalid signature.', status: 400);
}

MailEvent::dispatch(
$driver, $request->except('signature')
);
Expand Down
15 changes: 15 additions & 0 deletions src/Drivers/MailgunDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ class MailgunDriver extends MailDriver implements MailDriverContract
{
public function registerWebhooks($components): void {}

public function verifyWebhookSignature(array $payload): bool
{
if (empty($payload['signature']['timestamp']) || empty($payload['signature']['token']) || empty($payload['signature']['signature'])) {
return false;
}

$hmac = hash_hmac('sha256', $payload['signature']['timestamp'].$payload['signature']['token'], config('services.mailgun.api_key'));

if (function_exists('hash_equals')) {
return hash_equals($hmac, $payload['signature']['signature']);
}

return $hmac === $payload['signature']['signature'];
}

public function getUuidFromPayload(array $payload): ?string
{
return $payload['event-data']['message']['headers'][$this->uuidHeaderName] ??
Expand Down
9 changes: 7 additions & 2 deletions src/Drivers/PostmarkDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ public function registerWebhooks($components): void
}
}

public function verifyWebhookSignature(array $payload): bool
{
return true;
}

public function getUuidFromPayload(array $payload): ?string
{
return $payload['Metadata'][$this->uuidHeaderName] ??
Expand All @@ -65,9 +70,9 @@ public function eventMapping(): array
{
return [
EventType::CLICKED->value => ['RecordType' => 'Click'],
EventType::COMPLAINED->value => ['RecordType' => 'Complaint'],
EventType::COMPLAINED->value => ['RecordType' => 'SpamComplaint'],
EventType::DELIVERED->value => ['RecordType' => 'Delivery'],
EventType::HARD_BOUNCED->value => ['Type' => 'Bounce', 'RecordType' => 'HardBounce'],
EventType::HARD_BOUNCED->value => ['RecordType' => 'Bounce', 'Type' => 'HardBounce'],
EventType::OPENED->value => ['RecordType' => 'Open'],
EventType::SOFT_BOUNCED->value => ['RecordType' => 'Bounce', 'Type' => 'SoftBounce'],
];
Expand Down
43 changes: 43 additions & 0 deletions tests/PostmarkTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,49 @@
]);
});

it('can receive incoming soft bounce webhook from postmark', function () {
Mail::send([], [], function (Message $message) {
$message->to('mark@vormkracht10.nl')
->from('local@computer.nl')
->cc('cc@vk10.nl')
->bcc('bcc@vk10.nl')
->subject('Test')
->text('Text')
->html('<p>HTML</p>');
});

$mail = MailModel::latest()->first();

post(URL::signedRoute('mails.webhook', ['provider' => 'postmark']), [
'Metadata' => [
config('mails.headers.uuid') => $mail?->uuid,
],
'RecordType' => 'Bounce',
'ID' => 42,
'Type' => 'SoftBounce',
'TypeCode' => 1,
'Name' => 'Soft bounce',
'Tag' => 'Test',
'MessageID' => '00000000-0000-0000-0000-000000000000',
'ServerID' => 1234,
'MessageStream' => 'outbound',
'Description' => 'The server was unable to deliver your message (ex => unknown user, mailbox not found).',
'Details' => 'Test bounce details',
'Email' => 'john@example.com',
'From' => 'sender@example.com',
'BouncedAt' => '2023-05-21T02:51:39Z',
'DumpAvailable' => true,
'Inactive' => true,
'CanActivate' => true,
'Subject' => 'Test subject',
'Content' => 'Test content',
])->assertAccepted();

assertDatabaseHas((new MailEvent)->getTable(), [
'type' => EventType::HARD_BOUNCED->value,
]);
});

it('can receive incoming complaint webhook from postmark', function () {
Mail::send([], [], function (Message $message) {
$message->to('mark@vormkracht10.nl')
Expand Down

0 comments on commit b20ca3b

Please # to comment.