From f1143105d204c50e6d0e106e958b7281995235d6 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 4 Jun 2025 09:26:38 +0000 Subject: [PATCH] Let AddonHelper::getAddonInfo() throw exception on invalid addons --- src/Core/Addon/AddonHelper.php | 2 + src/Core/Addon/AddonInfo.php | 8 +--- src/Core/Addon/AddonManagerHelper.php | 32 +++++++++++++-- .../Addon/Exception/InvalidAddonException.php | 17 ++++++++ src/Module/Admin/Addons/Details.php | 12 +++++- src/Module/Admin/Addons/Index.php | 8 +++- tests/Unit/Core/Addon/AddonInfoTest.php | 5 +-- .../Core/Addon/AddonManagerHelperTest.php | 40 ++++++++++++++++++- 8 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 src/Core/Addon/Exception/InvalidAddonException.php diff --git a/src/Core/Addon/AddonHelper.php b/src/Core/Addon/AddonHelper.php index 03a21232e5..500bf66f1d 100644 --- a/src/Core/Addon/AddonHelper.php +++ b/src/Core/Addon/AddonHelper.php @@ -61,6 +61,8 @@ interface AddonHelper /** * Get the comment block of an addon as value object. + * + * @throws \Friendica\Core\Addon\Exception\InvalidAddonException if there is an error with the addon file */ public function getAddonInfo(string $addonId): AddonInfo; diff --git a/src/Core/Addon/AddonInfo.php b/src/Core/Addon/AddonInfo.php index 98e7fb3ed3..d0b46f11c6 100644 --- a/src/Core/Addon/AddonInfo.php +++ b/src/Core/Addon/AddonInfo.php @@ -41,13 +41,7 @@ final class AddonInfo 'id' => $addonId, ]; - $result = preg_match("|/\*.*\*/|msU", $raw, $m); - - if ($result === false || $result === 0 || !is_array($m) || count($m) < 1) { - return self::fromArray($data); - } - - $ll = explode("\n", $m[0]); + $ll = explode("\n", $raw); foreach ($ll as $l) { $l = trim($l, "\t\n\r */"); diff --git a/src/Core/Addon/AddonManagerHelper.php b/src/Core/Addon/AddonManagerHelper.php index 4b7ed1c4a0..f19b8604ff 100644 --- a/src/Core/Addon/AddonManagerHelper.php +++ b/src/Core/Addon/AddonManagerHelper.php @@ -9,6 +9,7 @@ declare(strict_types=1); namespace Friendica\Core\Addon; +use Friendica\Core\Addon\Exception\InvalidAddonException; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Database\Database; @@ -98,7 +99,14 @@ final class AddonManagerHelper implements AddonHelper $addons = []; foreach ($files as $addonId) { - $addonInfo = $this->getAddonInfo($addonId); + try { + $addonInfo = $this->getAddonInfo($addonId); + } catch (InvalidAddonException $th) { + $this->logger->error('Invalid addon found: ' . $addonId, ['exception' => $th]); + + // skip invalid addons + continue; + } if ( $this->config->get('system', 'show_unsupported_addons') @@ -227,6 +235,8 @@ final class AddonManagerHelper implements AddonHelper /** * Get the comment block of an addon as value object. + * + * @throws \Friendica\Core\Addon\Exception\InvalidAddonException if there is an error with the addon file */ public function getAddonInfo(string $addonId): AddonInfo { @@ -235,17 +245,31 @@ final class AddonManagerHelper implements AddonHelper 'name' => $addonId, ]; - if (!is_file($this->getAddonPath() . "/$addonId/$addonId.php")) { + $addonFile = $this->getAddonPath() . "/$addonId/$addonId.php"; + + if (!is_file($addonFile)) { return AddonInfo::fromArray($default); } $this->profiler->startRecording('file'); - $raw = file_get_contents($this->getAddonPath() . "/$addonId/$addonId.php"); + $raw = file_get_contents($addonFile); $this->profiler->stopRecording(); - return AddonInfo::fromString($addonId, $raw); + if ($raw === false) { + throw new InvalidAddonException('Could not read addon file: ' . $addonFile); + } + + $result = preg_match("|/\*.*\*/|msU", $raw, $matches); + + var_dump($addonFile, $result, $matches); + + if ($result === false || $result === 0 || !is_array($matches) || count($matches) < 1) { + throw new InvalidAddonException('Could not find valid comment block in addon file: ' . $addonFile); + } + + return AddonInfo::fromString($addonId, $matches[0]); } /** diff --git a/src/Core/Addon/Exception/InvalidAddonException.php b/src/Core/Addon/Exception/InvalidAddonException.php new file mode 100644 index 0000000000..28079bb1e1 --- /dev/null +++ b/src/Core/Addon/Exception/InvalidAddonException.php @@ -0,0 +1,17 @@ +parameters['addon']); + if (!is_file("addon/$addon/$addon.php")) { DI::sysmsg()->addNotice(DI::l10n()->t('Addon not found.')); $addonHelper->uninstallAddon($addon); @@ -91,7 +94,14 @@ class Details extends BaseAdmin $func($admin_form); } - $addonInfo = $addonHelper->getAddonInfo($addon); + try { + $addonInfo = $addonHelper->getAddonInfo($addon); + } catch (InvalidAddonException $th) { + $this->logger->error('Invalid addon found: ' . $addon, ['exception' => $th]); + DI::sysmsg()->addNotice(DI::l10n()->t('Invalid Addon found.')); + + $addonInfo = AddonInfo::fromArray(['id' => $addon, 'name' => $addon]); + } $addonAuthors = []; diff --git a/src/Module/Admin/Addons/Index.php b/src/Module/Admin/Addons/Index.php index 6038373018..6cbd472c8c 100644 --- a/src/Module/Admin/Addons/Index.php +++ b/src/Module/Admin/Addons/Index.php @@ -7,6 +7,7 @@ namespace Friendica\Module\Admin\Addons; +use Friendica\Core\Addon\Exception\InvalidAddonException; use Friendica\Core\Renderer; use Friendica\DI; use Friendica\Module\BaseAdmin; @@ -57,7 +58,12 @@ class Index extends BaseAdmin $addons = []; foreach ($addonHelper->getAvailableAddons() as $addonId) { - $addonInfo = $addonHelper->getAddonInfo($addonId); + try { + $addonInfo = $addonHelper->getAddonInfo($addonId); + } catch (InvalidAddonException $th) { + $this->logger->error('Invalid addon found: ' . $addonId, ['exception' => $th]); + continue; + } $info = [ 'name' => $addonInfo->getName(), diff --git a/tests/Unit/Core/Addon/AddonInfoTest.php b/tests/Unit/Core/Addon/AddonInfoTest.php index 20eb654f3a..7a342bc059 100644 --- a/tests/Unit/Core/Addon/AddonInfoTest.php +++ b/tests/Unit/Core/Addon/AddonInfoTest.php @@ -30,8 +30,7 @@ class AddonInfoTest extends TestCase 'without-author' => [ 'test', << [ 'test', << [ 'test', <<assertEquals('Hello Addon', $info->getName()); } + public function testGetAddonInfoThrowsInvalidAddonException(): void + { + $root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [ + 'helloaddon' => [ + 'helloaddon.php' => <<url(), + $this->createStub(Database::class), + $this->createStub(IManageConfigValues::class), + $this->createStub(ICanCache::class), + $this->createStub(LoggerInterface::class), + $this->createStub(Profiler::class) + ); + + $this->expectException(InvalidAddonException::class); + $this->expectExceptionMessage('Could not find valid comment block in addon file:'); + + $addonManagerHelper->getAddonInfo('helloaddon'); + } + public function testEnabledAddons(): void { $config = $this->createStub(IManageConfigValues::class); @@ -140,7 +167,18 @@ class AddonManagerHelperTest extends TestCase { $root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [ 'helloaddon' => [ - 'helloaddon.php' => ' << + */ + PHP, + ], + 'invalidaddon' => [ + 'invalidaddon.php' => 'This addon should not be loaded, because it does not contain a valid comment section.', ], '.hidden' => [ '.hidden.php' => 'This folder should be ignored',