From 20978076def6908dc85f07ac751e54aa7034ce53 Mon Sep 17 00:00:00 2001
From: Bernd Oliver Suenderhauf <bos@suenderhauf.de>
Date: Tue, 16 Apr 2019 02:06:29 +0200
Subject: [PATCH] Issue #3048344 by Pancho: Fatal error when specified
 FillPdfForm doesn't exist

---
 src/Controller/HandlePdfController.php       | 10 ++--
 src/FillPdfAccessController.php              | 18 ++++++-
 src/Service/FillPdfLinkManipulator.php       | 11 +++--
 tests/src/Functional/LinkManipulatorTest.php | 50 ++++++++++++++++++++
 4 files changed, 78 insertions(+), 11 deletions(-)
 create mode 100644 tests/src/Functional/LinkManipulatorTest.php

diff --git a/src/Controller/HandlePdfController.php b/src/Controller/HandlePdfController.php
index de76bae..dd32bd1 100644
--- a/src/Controller/HandlePdfController.php
+++ b/src/Controller/HandlePdfController.php
@@ -112,6 +112,10 @@ class HandlePdfController extends ControllerBase {
    *
    * @return \Symfony\Component\HttpFoundation\Response
    *   The action plugin's response object.
+   *
+   * @throws \InvalidArgumentException
+   *   If one of the passed arguments is missing or does not pass the
+   *   validation.
    */
   public function populatePdf() {
     $context = $this->linkManipulator->parseRequest($this->requestStack->getCurrentRequest());
@@ -125,13 +129,7 @@ class HandlePdfController extends ControllerBase {
 
     // @todo: Emit event (or call alter hook?) before populating PDF.
     // Rename fillpdf_merge_fields_alter() to fillpdf_populate_fields_alter().
-    /** @var \Drupal\fillpdf\FillPdfFormInterface $fillpdf_form */
     $fillpdf_form = FillPdfForm::load($context['fid']);
-    if (!$fillpdf_form) {
-      $this->messenger->addError($this->t('FillPDF Form (fid) not found in the system. Please check the value in your FillPDF Link.'));
-      return new RedirectResponse(Url::fromRoute('<front>')->toString());
-    }
-
     $fields = $fillpdf_form->getFormFields();
 
     // Populate entities array based on what user passed in.
diff --git a/src/FillPdfAccessController.php b/src/FillPdfAccessController.php
index e198584..effa746 100644
--- a/src/FillPdfAccessController.php
+++ b/src/FillPdfAccessController.php
@@ -2,13 +2,19 @@
 
 namespace Drupal\fillpdf;
 
+use Drupal\Core\Access\AccessResult;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
+use Drupal\Core\Logger\LoggerChannelTrait;
+use Drupal\Core\Messenger\MessengerTrait;
 use Drupal\Core\Session\AccountInterface;
 
 class FillPdfAccessController implements ContainerInjectionInterface {
 
+  use MessengerTrait;
+  use LoggerChannelTrait;
+
   /** @var \Drupal\fillpdf\FillPdfAccessHelperInterface */
   protected $accessHelper;
 
@@ -40,7 +46,17 @@ class FillPdfAccessController implements ContainerInjectionInterface {
   }
 
   public function checkLink() {
-    $context = $this->linkManipulator->parseRequest($this->requestStack->getCurrentRequest());
+    try {
+      $context = $this->linkManipulator->parseRequest($this->requestStack->getCurrentRequest());
+    }
+    catch (\InvalidArgumentException $exception) {
+      $message = $exception->getMessage();
+      $is_admin = $this->currentUser->hasPermission('administer pdfs');
+      $this->messenger()->addError($is_admin ? $message : t('An error occurred. Please notify the administrator.'));
+      $this->getLogger('fillpdf')->error($message);
+      return AccessResult::forbidden();
+    }
+
     $account = $this->currentUser;
 
     return $this->accessHelper->canGeneratePdfFromContext($context, $account);
diff --git a/src/Service/FillPdfLinkManipulator.php b/src/Service/FillPdfLinkManipulator.php
index d898097..970b951 100644
--- a/src/Service/FillPdfLinkManipulator.php
+++ b/src/Service/FillPdfLinkManipulator.php
@@ -54,8 +54,7 @@ class FillPdfLinkManipulator implements FillPdfLinkManipulatorInterface {
     $query = $link->getOption('query');
 
     if (!$query) {
-      throw new \InvalidArgumentException('The \Drupal\Core\Url you pass in must
-      have its \'query\' option set.');
+      throw new \InvalidArgumentException("This link doesn't specify a query string, so failing.");
     }
 
     $request_context = [
@@ -78,8 +77,7 @@ class FillPdfLinkManipulator implements FillPdfLinkManipulatorInterface {
       $request_context['fid'] = $query['fid'];
     }
     else {
-      throw new \InvalidArgumentException('fid parameter missing from query
-      string; cannot determine how to proceed, so failing.');
+      throw new \InvalidArgumentException('No FillPdfForm was specified in the query string, so failing.');
     }
 
     if (!empty($query['entity_type'])) {
@@ -116,6 +114,11 @@ class FillPdfLinkManipulator implements FillPdfLinkManipulatorInterface {
     else {
       // Populate defaults.
       $fillpdf_form = FillPdfForm::load($request_context['fid']);
+
+      if (!$fillpdf_form) {
+        throw new \InvalidArgumentException("The requested FillPdfForm doesn't exist, so failing.");
+      }
+
       $default_entity_id = $fillpdf_form->default_entity_id->value;
       if ($default_entity_id) {
         $default_entity_type = $fillpdf_form->default_entity_type->value;
diff --git a/tests/src/Functional/LinkManipulatorTest.php b/tests/src/Functional/LinkManipulatorTest.php
new file mode 100644
index 0000000..9bb148d
--- /dev/null
+++ b/tests/src/Functional/LinkManipulatorTest.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Drupal\Tests\fillpdf\Functional;
+
+use Drupal\Core\Url;
+
+/**
+ * @coversDefaultClass \Drupal\fillpdf\Service\FillPdfLinkManipulator
+ *
+ * @group fillpdf
+ *
+ * @todo Convert into a unit test.
+ */
+class LinkManipulatorTest extends FillPdfUploadTestBase {
+
+  /**
+   * Tests handling of a non-existing FillPdfForm ID.
+   */
+  public function testLinkExceptions() {
+    // Hit the generation route with no query string set.
+    $fillpdf_route = Url::fromRoute('fillpdf.populate_pdf', [], []);
+    $this->drupalGet($fillpdf_route);
+    // Ensure the exception is converted to an error and access is denied.
+    $this->assertSession()->statusCodeEquals(403);
+    $this->assertSession()->pageTextContains("This link doesn't specify a query string, so failing.");
+
+    // Hit the generation route with no fid set.
+    $fillpdf_route = Url::fromRoute('fillpdf.populate_pdf', [], [
+      'query' => [
+        'sample' => 1,
+      ],
+    ]);
+    $this->drupalGet($fillpdf_route);
+    // Ensure the exception is converted to an error and access is denied.
+    $this->assertSession()->statusCodeEquals(403);
+    $this->assertSession()->pageTextContains("No FillPdfForm was specified in the query string, so failing.");
+
+    // Hit the generation route with a non-existing fid set.
+    $fillpdf_route = Url::fromRoute('fillpdf.populate_pdf', [], [
+      'query' => [
+        'fid' => 1234,
+      ],
+    ]);
+    $this->drupalGet($fillpdf_route);
+    // Ensure the exception is converted to an error and access is denied.
+    $this->assertSession()->statusCodeEquals(403);
+    $this->assertSession()->pageTextContains("The requested FillPdfForm doesn't exist, so failing.");
+  }
+
+}
-- 
GitLab