<?php
/**
* Copyright (c) 2011-present Qualiteam software Ltd. All rights reserved.
* See https://www.x-cart.com/license-agreement.html for license details.
*/
namespace XCart\API\EventSubscriber\Storefront;
use ApiPlatform\Exception\InvalidArgumentException;
use ApiPlatform\Exception\ItemNotFoundException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use XLite\Model\Cart as CartModel;
use XLite\Model\Profile as ProfileModel;
use XLite\Model\OrderItem as CartItemModel;
use XLite\Model\Repo\Cart as CartRepository;
use XLite\Model\Repo\Orderitem as CartItemRepository;
class CartAccessValidationEventSubscriber implements EventSubscriberInterface
{
public function __construct(
private CartRepository $cartRepository,
private CartItemRepository $cartItemRepository,
) {
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [
['checkCart', 6],
['checkCartItem', 5],
],
];
}
public function checkCart(RequestEvent $event): void
{
if (!$event->isMainRequest() || $event->getRequest()->getMethod() === 'OPTIONS') {
return;
}
if (!preg_match('/api\/storefront\/carts\/([^\/]+)(?:\/|$)/S', $event->getRequest()->getPathInfo(), $match)) {
return;
}
$cartId = $match[1];
/** @var ?CartModel $cart */
$cart = $this->cartRepository->findOneBy(['public_id' => $cartId]);
if (!$cart) {
throw new ItemNotFoundException('Cart not found');
}
/** @var ProfileModel $user */
$user = $event->getRequest()->attributes->get('_profile');
$cartProfile = $cart->getProfile();
$cartOrigProfile = $cart->getOrigProfile();
// User anonymous and cart for registered user - security violation
if (!$user && !$cartProfile->getAnonymous()) {
throw new ItemNotFoundException('Cart for anonymous user not found');
}
// User is not anonymous and cart for anonymous user - security violation
if ($user && $cartProfile->getAnonymous()) {
throw new ItemNotFoundException('Cart for registered user not found');
}
if ($user && $user->getProfileId() !== $cartOrigProfile->getProfileId()) {
throw new ItemNotFoundException('Cart assigned to another user');
}
$event->getRequest()->attributes->set('_cart_id', $cart->getOrderId());
$event->getRequest()->attributes->set('_cart', $cart);
$event->getRequest()->attributes->set('_profile_id', $cartProfile->getProfileId());
$event->getRequest()->attributes->set('_profile', $cartProfile);
}
public function checkCartItem(RequestEvent $event): void
{
if (!$event->isMainRequest() || $event->getRequest()->getMethod() === 'OPTIONS') {
return;
}
if (!preg_match('/api\/storefront\/carts\/[^\/]+\/items\/(\d+)/S', $event->getRequest()->getPathInfo(), $match)) {
return;
}
$itemId = (int) $match[1];
if ($itemId <= 0) {
throw new InvalidArgumentException('Cart item ID Must be positive numeric');
}
/** @var ?CartItemModel $cart */
$item = $this->cartItemRepository->find($itemId);
if (!$item) {
throw new ItemNotFoundException('Cart item not found');
}
if ($item->getOrder()->getOrderId() !== $event->getRequest()->attributes->get('_cart')->getOrderId()) {
throw new ItemNotFoundException('Cart item not found in cart');
}
}
}