From fc55d06761bd135ee8609993debc78e705be4d11 Mon Sep 17 00:00:00 2001 From: Vitalij Mik Date: Wed, 4 Dec 2024 08:58:33 +0100 Subject: [PATCH] NTR: PISHPS-379: prevet to accept webhooks too early (#902) Co-authored-by: Vitalij Mik --- .../Storefront/Webhook/NotificationFacade.php | 24 ++++++++------ .../Webhook/WebhookControllerBase.php | 10 ++++++ src/Exception/WebhookIsTooEarlyException.php | 32 +++++++++++++++++++ 3 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 src/Exception/WebhookIsTooEarlyException.php diff --git a/src/Controller/Storefront/Webhook/NotificationFacade.php b/src/Controller/Storefront/Webhook/NotificationFacade.php index b891e8942..cf4227ac6 100644 --- a/src/Controller/Storefront/Webhook/NotificationFacade.php +++ b/src/Controller/Storefront/Webhook/NotificationFacade.php @@ -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; @@ -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(); @@ -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. diff --git a/src/Controller/Storefront/Webhook/WebhookControllerBase.php b/src/Controller/Storefront/Webhook/WebhookControllerBase.php index 2a5aa0156..779c7f992 100644 --- a/src/Controller/Storefront/Webhook/WebhookControllerBase.php +++ b/src/Controller/Storefront/Webhook/WebhookControllerBase.php @@ -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; @@ -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, diff --git a/src/Exception/WebhookIsTooEarlyException.php b/src/Exception/WebhookIsTooEarlyException.php new file mode 100644 index 000000000..41783f0f7 --- /dev/null +++ b/src/Exception/WebhookIsTooEarlyException.php @@ -0,0 +1,32 @@ + $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; + } +}