From 1e5dffa7191d509e138f429c0ec0380cb68f06ca Mon Sep 17 00:00:00 2001 From: Roland Dalmulder Date: Tue, 31 Mar 2020 21:44:32 +0200 Subject: [PATCH 1/3] =?UTF-8?q?First=20round=20of=20verifying=20composer?= =?UTF-8?q?=20on=20applying=20a=20patch=CB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PatchTester/Model/PullModel.php | 73 ++++++++++++++++++- .../language/en-GB/en-GB.com_patchtester.ini | 5 +- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/administrator/components/com_patchtester/PatchTester/Model/PullModel.php b/administrator/components/com_patchtester/PatchTester/Model/PullModel.php index 4a850d9..4caa803 100644 --- a/administrator/components/com_patchtester/PatchTester/Model/PullModel.php +++ b/administrator/components/com_patchtester/PatchTester/Model/PullModel.php @@ -124,7 +124,7 @@ class PullModel extends AbstractModel throw new RuntimeException(Text::_('COM_PATCHTESTER_REPO_IS_GONE')); } - $sha = $pull->head->sha; + $sha = $pull->head->sha; // Create tmp folder if it does not exist if (!file_exists($ciSettings->get('folder.temp'))) @@ -191,8 +191,16 @@ class PullModel extends AbstractModel // Remove zip to avoid get listing afterwards File::delete($zipPath); + // Verify the composer autoloader for any invalid entries + if ($this->verifyAutoloader($tempPath) === false) + { + // There is something broken in the autoloader, clean up and go back + Folder::delete($tempPath); + throw new RuntimeException(Text::_('COM_PATCHTESTER_PATCH_BREAKS_SITE')); + } + // Get files from deleted_logs - $deletedFiles = (file_exists($delLogPath) ? file($delLogPath) : array()); + $deletedFiles = (file_exists($delLogPath) ? file($delLogPath) : []); $deletedFiles = array_map('trim', $deletedFiles); if (file_exists($delLogPath)) @@ -332,6 +340,65 @@ class PullModel extends AbstractModel return $pull; } + /** + * Verify if the autoload contains any broken entries. + * + * @param string $path The path to look for the autoloader + * + * @return boolean True if there are broken dependencies | False otherwise. + * + * @since 4.0.0 + */ + private function verifyAutoloader(string $path): bool + { + $result = false; + $autoloadClass = false; + + // Check if we have an autoload file + if (!file_exists($path . '/libraries/vendor/autoload.php')) + { + return $result; + } + + // Get the generated token + $autoload = file_get_contents($path . '/libraries/vendor/autoload.php'); + $resultMatch = preg_match('/ComposerAutoloaderInit(.*)::/', $autoload, $match); + + if (!$resultMatch) + { + return $result; + } + + // Load the static autoloader + require_once $path . '/libraries/vendor/composer/autoload_static.php'; + $autoloadClass = '\Composer\Autoload\ComposerStaticInit' . $match[1]; + + // Get all the files + $files = $autoloadClass::$files; + + // Verify all the files exist + foreach ($files as $file) + { + // Fix the filepath to use the Joomla filesystem + $file = str_ireplace($path, JPATH_SITE, $file); + + if (!file_exists($file)) + { + $result = false; + } + } + + // Load the files loader + + // Load the classmap loader + + // Load the namespaces loader + + // Load the PSR-4 loader + + return $result; + } + /** * Saves the applied patch into database * @@ -497,7 +564,7 @@ class PullModel extends AbstractModel // We only create a backup if the file already exists if ($file->action === 'deleted' || (file_exists(JPATH_ROOT . '/' . $file->filename) - && $file->action === 'modified') + && $file->action === 'modified') || (file_exists(JPATH_ROOT . '/' . $file->originalFile) && $file->action === 'renamed')) { $filename = $file->action === 'renamed' ? $file->originalFile : $file->filename; diff --git a/administrator/components/com_patchtester/language/en-GB/en-GB.com_patchtester.ini b/administrator/components/com_patchtester/language/en-GB/en-GB.com_patchtester.ini index 7bf92bf..a5ed87a 100644 --- a/administrator/components/com_patchtester/language/en-GB/en-GB.com_patchtester.ini +++ b/administrator/components/com_patchtester/language/en-GB/en-GB.com_patchtester.ini @@ -106,5 +106,6 @@ COM_PATCHTESTER_TOOLBAR_FETCH_DATA="Fetch Data" COM_PATCHTESTER_TOOLBAR_RESET="Reset" COM_PATCHTESTER_VIEW_ON_GITHUB="View on GitHub" COM_PATCHTESTER_VIEW_ON_JOOMLA_ISSUE_TRACKER="View on Joomla! Issue Tracker" -COM_PATCHTESTER_ZIP_DOES_NOT_EXIST="The patch could not be applied, because it couldn't be retrieved from server." -COM_PATCHTESTER_ZIP_EXTRACT_FAILED="The patch could not be applied, because it couldn't be extracted." +COM_PATCHTESTER_ZIP_DOES_NOT_EXIST="The patch could not be applied because it couldn't be retrieved from server." +COM_PATCHTESTER_ZIP_EXTRACT_FAILED="The patch could not be applied because it couldn't be extracted." +COM_PATCHTESTER_PATCH_BREAKS_SITE="The patch could not be applied because it would break the site" From fad93340f4761e20e754770b2485570173394c3a Mon Sep 17 00:00:00 2001 From: Roland Dalmulder Date: Wed, 1 Apr 2020 19:37:31 +0200 Subject: [PATCH 2/3] Check against all composer files if any of the new files exist --- .../PatchTester/Model/PullModel.php | 96 +++++++++++++------ .../language/en-GB/en-GB.com_patchtester.ini | 2 +- 2 files changed, 70 insertions(+), 28 deletions(-) diff --git a/administrator/components/com_patchtester/PatchTester/Model/PullModel.php b/administrator/components/com_patchtester/PatchTester/Model/PullModel.php index 4caa803..cfd5cea 100644 --- a/administrator/components/com_patchtester/PatchTester/Model/PullModel.php +++ b/administrator/components/com_patchtester/PatchTester/Model/PullModel.php @@ -360,43 +360,85 @@ class PullModel extends AbstractModel return $result; } - // Get the generated token - $autoload = file_get_contents($path . '/libraries/vendor/autoload.php'); - $resultMatch = preg_match('/ComposerAutoloaderInit(.*)::/', $autoload, $match); + $composerFiles = [ + 'autoload_static.php', + 'autoload_files.php', + 'autoload_classmap.php', + 'autoload_namespaces.php', + 'autoload_psr4.php', + ]; + $filesToCheck = []; - if (!$resultMatch) - { - return $result; - } + array_walk( + $composerFiles, + static function ($composerFile) use (&$filesToCheck, $path) { + if (file_exists($path . '/libraries/vendor/composer/' . $composerFile) === false) + { + return; + } - // Load the static autoloader - require_once $path . '/libraries/vendor/composer/autoload_static.php'; - $autoloadClass = '\Composer\Autoload\ComposerStaticInit' . $match[1]; + if ($composerFile === 'autoload_static.php') + { + // Get the generated token + $autoload = file_get_contents($path . '/libraries/vendor/autoload.php'); + $resultMatch = preg_match('/ComposerAutoloaderInit(.*)::/', $autoload, $match); - // Get all the files - $files = $autoloadClass::$files; + if (!$resultMatch) + { + return; + } - // Verify all the files exist + require_once $path . '/libraries/vendor/composer/autoload_static.php'; + $autoloadClass = '\Composer\Autoload\ComposerStaticInit' . $match[1]; + + // Get all the files + $files = $autoloadClass::$files; + + $filesToCheck = array_merge($filesToCheck, $files); + } + else + { + $files = require $path . '/libraries/vendor/composer/' . $composerFile; + + $filesToCheck = array_merge($filesToCheck, $files); + } + } + ); + + return $this->checkFilesExist($filesToCheck, $path); + } + + /** + * Check a list of files if they exist. + * + * @param array $files The list of files to check + * @param string $path The path where the temporary patch resides + * + * @return boolean True if all files exist | False otherwise. + * + * @since 4.0.0 + */ + private function checkFilesExist(array $files, string $path): bool + { foreach ($files as $file) { - // Fix the filepath to use the Joomla filesystem - $file = str_ireplace($path, JPATH_SITE, $file); - - if (!file_exists($file)) + if (is_array($file)) { - $result = false; + $this->checkFilesExist($file, $path); + } + elseif (!file_exists($file)) + { + // Check if the file exists in the Joomla filesystem + $file = str_ireplace($path, JPATH_SITE, $file); + + if (!file_exists($file)) + { + return false; + } } } - // Load the files loader - - // Load the classmap loader - - // Load the namespaces loader - - // Load the PSR-4 loader - - return $result; + return true; } /** diff --git a/administrator/components/com_patchtester/language/en-GB/en-GB.com_patchtester.ini b/administrator/components/com_patchtester/language/en-GB/en-GB.com_patchtester.ini index a5ed87a..492bc1e 100644 --- a/administrator/components/com_patchtester/language/en-GB/en-GB.com_patchtester.ini +++ b/administrator/components/com_patchtester/language/en-GB/en-GB.com_patchtester.ini @@ -108,4 +108,4 @@ COM_PATCHTESTER_VIEW_ON_GITHUB="View on GitHub" COM_PATCHTESTER_VIEW_ON_JOOMLA_ISSUE_TRACKER="View on Joomla! Issue Tracker" COM_PATCHTESTER_ZIP_DOES_NOT_EXIST="The patch could not be applied because it couldn't be retrieved from server." COM_PATCHTESTER_ZIP_EXTRACT_FAILED="The patch could not be applied because it couldn't be extracted." -COM_PATCHTESTER_PATCH_BREAKS_SITE="The patch could not be applied because it would break the site" +COM_PATCHTESTER_PATCH_BREAKS_SITE="The patch could not be applied because it would break the site. Check the pull request to see if it is up-to-date." From 0a07c9257011c308d177e62a834384f15ce177ba Mon Sep 17 00:00:00 2001 From: Roland Dalmulder Date: Fri, 3 Apr 2020 17:39:53 +0200 Subject: [PATCH 3/3] Remove obsolete variable --- .../components/com_patchtester/PatchTester/Model/PullModel.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/administrator/components/com_patchtester/PatchTester/Model/PullModel.php b/administrator/components/com_patchtester/PatchTester/Model/PullModel.php index cfd5cea..57e45dc 100644 --- a/administrator/components/com_patchtester/PatchTester/Model/PullModel.php +++ b/administrator/components/com_patchtester/PatchTester/Model/PullModel.php @@ -351,8 +351,7 @@ class PullModel extends AbstractModel */ private function verifyAutoloader(string $path): bool { - $result = false; - $autoloadClass = false; + $result = false; // Check if we have an autoload file if (!file_exists($path . '/libraries/vendor/autoload.php'))