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