commercetools-8.x-1.2-alpha1/modules/commercetools_decoupled/src/EventSubscriber/CommercetoolsDecoupledGraphQlProxyAccessSubscriber.php

modules/commercetools_decoupled/src/EventSubscriber/CommercetoolsDecoupledGraphQlProxyAccessSubscriber.php
<?php

declare(strict_types=1);

namespace Drupal\commercetools_decoupled\EventSubscriber;

use Drupal\commercetools\Event\CommercetoolsGraphQlOperationEvent;
use Drupal\commercetools\Event\CommercetoolsGraphQlOperationResultEvent;
use Drupal\commercetools\Exception\CommercetoolsGraphqlAccessException;
use Drupal\Core\Session\AccountInterface;
use GraphQL\Language\AST\DocumentNode;
use GraphQL\Language\Parser;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Limit allowed GraphQL requests from the proxy page.
 */
class CommercetoolsDecoupledGraphQlProxyAccessSubscriber implements EventSubscriberInterface {


  /**
   * Array of parsed query objects.
   *
   * @var array
   */
  protected array $queryObjects;

  /**
   * CommercetoolsDecoupledGraphQlProxyAccessSubscriber constructor.
   *
   * @param \Drupal\Core\Session\AccountInterface $currentUser
   *   The current user.
   */
  public function __construct(
    protected readonly AccountInterface $currentUser,
  ) {
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    return [
      CommercetoolsGraphQlOperationEvent::class => ['onExecute', 300],
      CommercetoolsGraphQlOperationResultEvent::class => ['onResult', 300],
    ];
  }

  /**
   * Before GraphQl execution event handler.
   *
   * @throws \GraphQL\Error\SyntaxError
   */
  public function onExecute(CommercetoolsGraphQlOperationEvent $event): void {
    // Works only for proxy requests.
    if (empty($event->variables['proxy'])) {
      return;
    }

    $query = $event->query;
    $variables = $event->variables;
    $allowedOperation = $this->getAllowedOperations();

    $queryObject = $this->getQueryObject($query);
    $queryRootNodes = $queryObject->toArray()['definitions'];

    for ($i = 0; $i < $queryRootNodes->count(); $i++) {
      $node = $queryRootNodes->offsetGet($i);
      // Getting the operation name.
      $operation = $node->selectionSet->selections->offsetGet(0)->name->value;
      if (!isset($allowedOperation[$operation])) {
        $event->operationAllowed = FALSE;
        break;
      }

      foreach ($allowedOperation[$operation] as $parameterName => $parameterValue) {
        if (!isset($variables[$parameterName]) || !in_array($variables[$parameterName], $parameterValue)) {
          $event->operationAllowed = FALSE;
          break;
        }
      }
    }
  }

  /**
   * After GraphQl execution event handler.
   *
   * @throws \GraphQL\Error\SyntaxError
   */
  public function onResult(CommercetoolsGraphQlOperationResultEvent $event): void {
    // Works only for proxy requests.
    if (empty($event->variables['proxy'])) {
      return;
    }

    $query = $event->query;
    $result = $event->result;

    $queryObject = $this->getQueryObject($query);
    $queryRootNodes = $queryObject->toArray()['definitions'];

    for ($i = 0; $i < $queryRootNodes->count(); $i++) {
      $node = $queryRootNodes->offsetGet($i);
      // Getting the operation name.
      $operation = $node->selectionSet->selections->offsetGet(0)->name->value;
      $this->operationAccessCheckByResult($operation, $result);
    }
  }

  /**
   * Perform post-response access checks for a GraphQL operation.
   */
  protected function operationAccessCheckByResult(string $operation, array $result): void {
    switch ($operation) {
      case 'orders':
        if ($this->currentUser->isAnonymous()) {
          $orders = $result['orders']['results'];
          foreach ($orders as $order) {
            if (!empty($order['customerId'])) {
              throw new CommercetoolsGraphqlAccessException();
            }
          }
        }
        break;
    }
  }

  /**
   * Get parsed query object.
   *
   * @param string $query
   *   A GraphQL query.
   *
   * @return \GraphQL\Language\AST\DocumentNode
   *   Parsed GraphQL object.
   *
   * @throws \GraphQL\Error\SyntaxError
   */
  protected function getQueryObject(string $query): DocumentNode {
    // @todo Find a more lightweight library to parse the query.
    $this->queryObjects[$query] ??= Parser::parse($query);
    return $this->queryObjects[$query];
  }

  /**
   * Return array of allowed operation with required parameters.
   */
  protected function getAllowedOperations(): array {
    return [
      'productProjectionSearch' => [],
      'products' => [],
      'cart' => [
        'id' => ['[current_cart:id]'],
      ],
      'updateCart' => [
        'id' => ['[current_cart_or_create:id]', '[current_cart:id]'],
      ],
      'createOrderFromCart' => [],
      'orders' => [],
      'categories' => [],
      'customer' => [],
      'updateCustomer' => [],
    ];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc