Commit a19cb005 authored by catch's avatar catch
Browse files

fix: #3387013 Check LinkItemInterface::isEmpty() before validating

By: s_leu
By: smustgrave
By: akhil babu
By: dcam
(cherry picked from commit b9564e01)
parent e0f7d183
Loading
Loading
Loading
Loading
Loading
+23 −16
Original line number Diff line number Diff line
@@ -4,9 +4,11 @@

use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\link\LinkItemInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedValueException;

/**
 * Validates the LinkAccess constraint.
@@ -44,7 +46,13 @@ public static function create(ContainerInterface $container) {
   * {@inheritdoc}
   */
  public function validate($value, Constraint $constraint): void {
    if (isset($value)) {
    if (!$value instanceof LinkItemInterface) {
      throw new UnexpectedValueException($value, LinkItemInterface::class);
    }
    if ($value->isEmpty()) {
      return;
    }

    try {
      $url = $value->getUrl();
    }
@@ -61,6 +69,5 @@ public function validate($value, Constraint $constraint): void {
        ->addViolation();
    }
  }
  }

}
+22 −15
Original line number Diff line number Diff line
@@ -3,8 +3,10 @@
namespace Drupal\link\Plugin\Validation\Constraint;

use Drupal\Component\Utility\UrlHelper;
use Drupal\link\LinkItemInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedValueException;

/**
 * Validates the LinkExternalProtocols constraint.
@@ -15,7 +17,13 @@ class LinkExternalProtocolsConstraintValidator extends ConstraintValidator {
   * {@inheritdoc}
   */
  public function validate($value, Constraint $constraint): void {
    if (isset($value)) {
    if (!$value instanceof LinkItemInterface) {
      throw new UnexpectedValueException($value, LinkItemInterface::class);
    }
    if ($value->isEmpty()) {
      return;
    }

    try {
      /** @var \Drupal\Core\Url $url */
      $url = $value->getUrl();
@@ -31,6 +39,5 @@ public function validate($value, Constraint $constraint): void {
        ->addViolation();
    }
  }
  }

}
+35 −28
Original line number Diff line number Diff line
@@ -2,11 +2,13 @@

namespace Drupal\link\Plugin\Validation\Constraint;

use Drupal\link\LinkItemInterface;
use Symfony\Component\Routing\Exception\InvalidParameterException;
use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedValueException;

/**
 * Validates the LinkNotExistingInternal constraint.
@@ -17,7 +19,13 @@ class LinkNotExistingInternalConstraintValidator extends ConstraintValidator {
   * {@inheritdoc}
   */
  public function validate($value, Constraint $constraint): void {
    if (isset($value)) {
    if (!$value instanceof LinkItemInterface) {
      throw new UnexpectedValueException($value, LinkItemInterface::class);
    }
    if ($value->isEmpty()) {
      return;
    }

    try {
      /** @var \Drupal\Core\Url $url */
      $url = $value->getUrl();
@@ -50,6 +58,5 @@ public function validate($value, Constraint $constraint): void {
      }
    }
  }
  }

}
+32 −26
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
use Drupal\link\LinkItemInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedValueException;

/**
 * Constraint validator for links receiving data allowed by its settings.
@@ -15,7 +16,13 @@ class LinkTypeConstraintValidator extends ConstraintValidator {
   * {@inheritdoc}
   */
  public function validate($value, Constraint $constraint): void {
    if (isset($value)) {
    if (!$value instanceof LinkItemInterface) {
      throw new UnexpectedValueException($value, LinkItemInterface::class);
    }
    if ($value->isEmpty()) {
      return;
    }

    $uri_is_valid = TRUE;

    /** @var \Drupal\link\LinkItemInterface $link_item */
@@ -48,6 +55,5 @@ public function validate($value, Constraint $constraint): void {
        ->addViolation();
    }
  }
  }

}
+37 −4
Original line number Diff line number Diff line
@@ -4,26 +4,27 @@

namespace Drupal\Tests\link\Unit\Plugin\Validation\Constraint;

use Drupal\Core\Session\AccountProxyInterface;
use Drupal\link\LinkItemInterface;
use Drupal\link\Plugin\Validation\Constraint\LinkAccessConstraint;
use Drupal\link\Plugin\Validation\Constraint\LinkAccessConstraintValidator;
use Drupal\Tests\UnitTestCase;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\CoversMethod;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface;

/**
 * Tests the LinkAccessConstraintValidator validator.
 */
#[CoversClass(LinkAccessConstraintValidator::class)]
#[CoversMethod(LinkAccessConstraintValidator::class, 'validate')]
#[Group('validation')]
class LinkAccessConstraintValidatorTest extends UnitTestCase {

  /**
   * Tests the access validation constraint for links.
   *
   * @legacy-covers ::validate
   */
  #[DataProvider('providerValidate')]
  public function testValidate(bool $mayLinkAnyPage, bool $urlAccess, bool $valid): void {
@@ -93,4 +94,36 @@ public static function providerValidate(): \Generator {
    yield [FALSE, FALSE, FALSE];
  }

  /**
   * Tests validating a value that isn't a LinkItemInterface.
   */
  public function testUnexpectedValue(): void {
    $this->expectException(UnexpectedValueException::class);
    $user = $this->createMock(AccountProxyInterface::class);
    $validator = new LinkAccessConstraintValidator($user);
    $context = $this->createMock(ExecutionContextInterface::class);
    $validator->initialize($context);
    $constraint = new LinkAccessConstraint();
    $validator->validate('bad value', $constraint);
  }

  /**
   * Tests validating an empty Link field.
   */
  public function testEmptyField(): void {
    $link = $this->createMock(LinkItemInterface::class);
    $link->expects($this->once())
      ->method('isEmpty')
      ->willReturn(TRUE);
    $link->expects($this->never())
      ->method('getUrl');

    $user = $this->createMock(AccountProxyInterface::class);
    $validator = new LinkAccessConstraintValidator($user);
    $context = $this->createMock(ExecutionContextInterface::class);
    $validator->initialize($context);
    $constraint = new LinkAccessConstraint();
    $validator->validate($link, $constraint);
  }

}
Loading