From a4dad66ea84977e28b0520badc57edbe896f4bb9 Mon Sep 17 00:00:00 2001
From: lucashedding <lucashedding@1463982.no-reply.drupal.org>
Date: Mon, 14 Oct 2019 12:51:58 -0600
Subject: [PATCH] Issue #3087498 by heddn: Validate downloaded update archives

---
 src/Services/InPlaceUpdate.php        | 27 +++++++++++++++++++++++++++
 src/Services/ModifiedFiles.php        |  2 +-
 tests/src/Build/InPlaceUpdateTest.php |  2 +-
 3 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/src/Services/InPlaceUpdate.php b/src/Services/InPlaceUpdate.php
index e40cf083f2..d37158f559 100644
--- a/src/Services/InPlaceUpdate.php
+++ b/src/Services/InPlaceUpdate.php
@@ -8,6 +8,9 @@ use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\File\Exception\FileException;
 use Drupal\Core\File\FileSystemInterface;
 use Drupal\Core\Url;
+use Drupal\Signify\ChecksumList;
+use Drupal\Signify\FailedCheckumFilter;
+use Drupal\Signify\Verifier;
 use DrupalFinder\DrupalFinder;
 use GuzzleHttp\ClientInterface;
 use GuzzleHttp\Exception\RequestException;
@@ -209,6 +212,7 @@ class InPlaceUpdate implements UpdateInterface {
    */
   protected function processUpdate(ArchiverInterface $archive, $project_root) {
     $archive->extract($this->getTempDirectory());
+    $this->validateArchive($this->getTempDirectory());
     foreach ($this->getFilesList($this->getTempDirectory()) as $file) {
       $file_real_path = $this->getFileRealPath($file);
       $file_path = substr($file_real_path, strlen($this->getTempDirectory() . self::ARCHIVE_DIRECTORY));
@@ -236,6 +240,29 @@ class InPlaceUpdate implements UpdateInterface {
     return TRUE;
   }
 
+  /**
+   * Validate the downloaded archive.
+   *
+   * @param string $directory
+   *   The location of the downloaded archive.
+   */
+  protected function validateArchive($directory) {
+    $csig_file = $directory . DIRECTORY_SEPARATOR . 'checksumlist.csig';
+    if (!file_exists($csig_file)) {
+      throw new \RuntimeException('The CSIG file does not exist in the archive.');
+    }
+    $contents = file_get_contents($csig_file);
+    $module_path = drupal_get_path('module', 'automatic_updates');
+    $key = file_get_contents($module_path . '/artifacts/keys/root.pub');
+    $verifier = new Verifier($key);
+    $files = $verifier->verifyCsigMessage($contents);
+    $checksums = new ChecksumList($files, TRUE);
+    $failed_checksums = new FailedCheckumFilter($checksums, $directory);
+    if (iterator_count($failed_checksums)) {
+      throw new \RuntimeException('The downloaded files did not match what was expected.');
+    }
+  }
+
   /**
    * Backup before an update.
    *
diff --git a/src/Services/ModifiedFiles.php b/src/Services/ModifiedFiles.php
index 5a0fe77f83..b900d53276 100644
--- a/src/Services/ModifiedFiles.php
+++ b/src/Services/ModifiedFiles.php
@@ -105,7 +105,7 @@ class ModifiedFiles implements ModifiedFilesInterface {
     $module_path = drupal_get_path('module', 'automatic_updates');
     $key = file_get_contents($module_path . '/artifacts/keys/root.pub');
     $verifier = new Verifier($key);
-    $files = $verifier->verifyCsigMessage($contents, new \DateTime('2020-01-01', new \DateTimeZone('UTC')));
+    $files = $verifier->verifyCsigMessage($contents);
     $checksums = new ChecksumList($files, TRUE);
     foreach (new FailedCheckumFilter($checksums, $directory_root) as $failed_checksum) {
       $file_path = implode(DIRECTORY_SEPARATOR, array_filter([
diff --git a/tests/src/Build/InPlaceUpdateTest.php b/tests/src/Build/InPlaceUpdateTest.php
index c72624bab2..b9c7f0b02b 100644
--- a/tests/src/Build/InPlaceUpdateTest.php
+++ b/tests/src/Build/InPlaceUpdateTest.php
@@ -156,7 +156,7 @@ class InPlaceUpdateTest extends QuickStartTestBase {
     $this->assertDrupalVisit();
 
     // Update the contrib project.
-    $this->visit("/automatic_updates/in-place-update/$project/$project_type/$from_version/$to_version");
+    $this->visit("/test_automatic_updates/in-place-update/$project/$project_type/$from_version/$to_version");
     $this->assertDrupalVisit();
 
     // Assert that the update worked.
-- 
GitLab