Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PISHPS-379: prevent to accept webhooks too early #902

Merged
merged 1 commit into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}
Loading