Skip to content

Commit

Permalink
NTR: PISHPS-379: prevet to accept webhooks too early (#902)
Browse files Browse the repository at this point in the history
Co-authored-by: Vitalij Mik <[email protected]>
  • Loading branch information
BlackScorp and Vitalij Mik authored Dec 4, 2024
1 parent 2ff7b44 commit fc55d06
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 9 deletions.
24 changes: 15 additions & 9 deletions src/Controller/Storefront/Webhook/NotificationFacade.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Kiener\MolliePayments\Compatibility\Bundles\FlowBuilder\FlowBuilderFactory;
use Kiener\MolliePayments\Components\Subscription\SubscriptionManager;
use Kiener\MolliePayments\Exception\CustomerCouldNotBeFoundException;
use Kiener\MolliePayments\Exception\WebhookIsTooEarlyException;
use Kiener\MolliePayments\Gateway\MollieGatewayInterface;
use Kiener\MolliePayments\Handler\Method\ApplePayPayment;
use Kiener\MolliePayments\Repository\OrderTransaction\OrderTransactionRepositoryInterface;
Expand Down Expand Up @@ -143,15 +144,6 @@ public function onNotify(string $swTransactionId, Context $context): void
throw new \Exception('Transaction ' . $swTransactionId . ' not found in Shopware');
}

# Apple pay direct creates a payment and then updates order/transaction custom fields, sometimes the webhook is quicker than the process. so we wait once and then read the custom fields again
if ($swTransaction->getCustomFields() === null) {
sleep(2);
$swTransaction = $this->getTransaction($swTransactionId, $context);
if (!$swTransaction instanceof OrderTransactionEntity) {
throw new \Exception('Transaction ' . $swTransactionId . ' not found in Shopware');
}
}

# -----------------------------------------------------------------------------------------------------

$swOrder = $swTransaction->getOrder();
Expand All @@ -160,6 +152,20 @@ public function onNotify(string $swTransactionId, Context $context): void
throw new OrderNotFoundException('Shopware Order not found for transaction: ' . $swTransactionId);
}

$now = new \DateTime();
$now->modify("+2 minutes");

$changedDate = $swOrder->getUpdatedAt();
if ($changedDate === null) {
$changedDate = $swOrder->getCreatedAt();
}

if ($changedDate !== null && $now < $changedDate) {
throw new WebhookIsTooEarlyException((string)$swOrder->getOrderNumber(), $now, $changedDate);
}



# --------------------------------------------------------------------------------------------

# now get the correct settings from the sales channel of that order.
Expand Down
10 changes: 10 additions & 0 deletions src/Controller/Storefront/Webhook/WebhookControllerBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Kiener\MolliePayments\Repository\Order\OrderRepositoryInterface;
use Kiener\MolliePayments\Repository\OrderTransaction\OrderTransactionRepositoryInterface;
use Psr\Log\LoggerInterface;
use Shopware\Core\Framework\ShopwareHttpException;
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\HttpFoundation\JsonResponse;
Expand Down Expand Up @@ -69,6 +70,15 @@ public function onWebhookReceived(SalesChannelContext $context, string $swTransa
$this->notificationFacade->onNotify($swTransactionId, $context->getContext());

return new JsonResponse(['success' => true]);
} catch (ShopwareHttpException $exception) {
$this->logger->warning(
'Warning in Webhook for Transaction ' . $swTransactionId,
[
'error' => $exception->getMessage()
]
);

return new JsonResponse(['success' => false, 'error' => $exception->getMessage()], $exception->getStatusCode());
} catch (\Throwable $ex) {
$this->logger->error(
'Error in Mollie Webhook for Transaction ' . $swTransactionId,
Expand Down
32 changes: 32 additions & 0 deletions src/Exception/WebhookIsTooEarlyException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Exception;

use Shopware\Core\Framework\ShopwareHttpException;
use Symfony\Component\HttpFoundation\Response;

class WebhookIsTooEarlyException extends ShopwareHttpException
{
public const MOLLIE_PAYMENTS__WEBHOOK_TOO_EARLY = 'MOLLIE_PAYMENTS__WEBHOOK_TOO_EARLY';
public function __construct(string $oderNumber, \DateTimeInterface $now, \DateTimeInterface $updatedTime)
{
$message = 'Webhook is too early for order: {{orderNumber}}. The last updateTime of the order is {{lastUpdateTime}}. It should be higher than: {{now}}';
$parameters =[
'orderNumber' => $oderNumber,
'lastUpdateTime' => $updatedTime->format('Y-m-d H:i:s'),
'now' => $now->format('Y-m-d H:i:s'),
];

parent::__construct($message, $parameters);
}
public function getErrorCode(): string
{
return self::MOLLIE_PAYMENTS__WEBHOOK_TOO_EARLY;
}

public function getStatusCode(): int
{
return Response::HTTP_TOO_EARLY;
}
}

0 comments on commit fc55d06

Please sign in to comment.