Commit 9395aea3 authored by Cameron Prince's avatar Cameron Prince Committed by Cameron Prince
Browse files

Issue #3280037 by cameron prince: Add flood protection to block credit card testing bots

parent bd91916f
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -28,3 +28,13 @@ commerce_payment.commerce_payment_gateway.plugin.itransact:
              mapping:
                value:
                  label: 'API response messages'
    flood_control:
      type: mapping
      label: 'Flood control'
      mapping:
        maximum:
          type: integer
          label: 'Maximum'
        seconds:
          type: integer
          label: 'Seconds'
+75 −2
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
namespace Drupal\commerce_itransact\Plugin\Commerce\PaymentGateway;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
@@ -23,6 +24,7 @@ use Drupal\user\UserInterface;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\GuzzleException;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

/**
@@ -123,10 +125,24 @@ class Onsite extends OnsitePaymentGatewayBase implements OnsiteInterface {
   */
  const API_BASE_URL = 'https://api.itransact.com';

  /**
   * The database connection.
   *
   * @var Drupal\Core\Database\Connection
   */
  protected $connection;

  /**
   * The request stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;
 
  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, PaymentTypeManager $payment_type_manager, PaymentMethodTypeManager $payment_method_type_manager, TimeInterface $time, EntityFieldManagerInterface $entity_field_manager, ClientInterface $http_client, LoggerChannelFactoryInterface $logger_factory, PrivateTempStoreFactory $temp_store_factory, SessionManagerInterface $session_manager, SessionInterface $session) {
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, PaymentTypeManager $payment_type_manager, PaymentMethodTypeManager $payment_method_type_manager, TimeInterface $time, EntityFieldManagerInterface $entity_field_manager, ClientInterface $http_client, LoggerChannelFactoryInterface $logger_factory, PrivateTempStoreFactory $temp_store_factory, SessionManagerInterface $session_manager, SessionInterface $session, Connection $connection, RequestStack $request_stack) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $payment_type_manager, $payment_method_type_manager, $time);

    $this->entityFieldManager = $entity_field_manager;
@@ -135,6 +151,8 @@ class Onsite extends OnsitePaymentGatewayBase implements OnsiteInterface {
    $this->tempStore = $temp_store_factory->get('commerce_itransact');
    $this->sessionManager = $session_manager;
    $this->session = $session;
    $this->connection = $connection;
    $this->requestStack = $request_stack;
  }

  /**
@@ -154,7 +172,9 @@ class Onsite extends OnsitePaymentGatewayBase implements OnsiteInterface {
      $container->get('logger.factory'),
      $container->get('tempstore.private'),
      $container->get('session_manager'),
      $container->get('session')
      $container->get('session'),
      $container->get('database'),
      $container->get('request_stack')
    );
  }

@@ -168,6 +188,10 @@ class Onsite extends OnsitePaymentGatewayBase implements OnsiteInterface {
      'options' => [
        'log' => [],
      ],
      'flood_control' => [
        'maximum' => 5,
        'seconds' => 300,
      ],
    ] + parent::defaultConfiguration();
  }

@@ -193,6 +217,34 @@ class Onsite extends OnsitePaymentGatewayBase implements OnsiteInterface {
      '#required' => TRUE,
    ];

    $form['flood_control'] = [
      '#type' => 'details',
      '#title' => $this->t('Flood control'),
      '#description' => $this->t('Limits orders to a maximum number within a time period.'),
    ];

    $form['flood_control']['maximum'] = [
      '#type' => 'textfield',
      '#attributes' => [
        'type' => 'number',
      ],
      '#title' => $this->t('Maximum allowed orders'),
      '#required' => TRUE,
      '#maxlength' => 3,
      '#default_value' => $this->configuration['flood_control']['maximum'],
    ];

    $form['flood_control']['seconds'] = [
      '#type' => 'textfield',
      '#attributes' => [
        'type' => 'number',
      ],
      '#title' => $this->t('Time period (in seconds)'),
      '#required' => TRUE,
      '#maxlength' => 4,
      '#default_value' => $this->configuration['flood_control']['seconds'],
    ];

    $form['options'] = [
      '#type' => 'details',
      '#title' => $this->t('API options'),
@@ -230,6 +282,8 @@ class Onsite extends OnsitePaymentGatewayBase implements OnsiteInterface {
      $this->configuration['api_username'] = $values['api_username'];
      $this->configuration['api_key'] = $values['api_key'];
      $this->configuration['options']['log'] = $values['options']['log'];
      $this->configuration['flood_control']['maximum'] = $values['flood_control']['maximum'];
      $this->configuration['flood_control']['seconds'] = $values['flood_control']['seconds'];
    }
  }

@@ -241,6 +295,25 @@ class Onsite extends OnsitePaymentGatewayBase implements OnsiteInterface {
    $payment_method = $payment->getPaymentMethod();
    $this->assertPaymentMethod($payment_method);

    // Get the number of orders from this IP address in the past X seconds.
    $time = $this->time->getRequestTime();
    $ip_address = $this->requestStack->getCurrentRequest()->getClientIp();
    $count = $this->connection->select('commerce_order', 'co')
      ->condition('co.ip_address', $ip_address)
      ->condition('co.created', [($time - $this->configuration['flood_control']['seconds']), $time], 'BETWEEN')
      ->condition('co.payment_gateway', $payment->getPaymentGatewayId())
      ->countQuery()
      ->execute()
      ->fetchField();

    if ($count > $this->configuration['flood_control']['maximum']) {
      $error = $this->t('iTransact error: Greater than @attempts order attempts within @seconds seconds.', [
        '@attempts' => $this->configuration['flood_control']['maximum'],
        '@seconds' => $this->configuration['flood_control']['seconds'],
      ]);
      throw new PaymentGatewayException($error);
    }

    // Prepare all the required values for the iTransact "/transactions" POST.
    $amount = $payment->getAmount();
    $order = $payment->getOrder();