/**
* 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;
'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 */");
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;
$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')
/**
* 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
{
'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]);
}
/**
--- /dev/null
+<?php
+
+// Copyright (C) 2010-2024, the Friendica project
+// SPDX-FileCopyrightText: 2010-2024 the Friendica project
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+declare(strict_types=1);
+
+namespace Friendica\Core\Addon\Exception;
+
+/**
+ * Exception in case an addon is invalid
+ */
+final class InvalidAddonException extends \RuntimeException
+{
+}
namespace Friendica\Module\Admin\Addons;
use Friendica\Content\Text\Markdown;
+use Friendica\Core\Addon\AddonInfo;
+use Friendica\Core\Addon\Exception\InvalidAddonException;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Model\Contact;
$addonHelper = DI::addonHelper();
$addon = Strings::sanitizeFilePathItem($this->parameters['addon']);
+
if (!is_file("addon/$addon/$addon.php")) {
DI::sysmsg()->addNotice(DI::l10n()->t('Addon not found.'));
$addonHelper->uninstallAddon($addon);
$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 = [];
namespace Friendica\Module\Admin\Addons;
+use Friendica\Core\Addon\Exception\InvalidAddonException;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Module\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(),
'without-author' => [
'test',
<<<TEXT
- <?php
- /*
+ /**
* Name: Test Addon
* Description: adds awesome features to friendica
* Version: 100.4.50-beta.5
'without-maintainer' => [
'test',
<<<TEXT
- <?php
/*
* Name: Test Addon
* Description: adds awesome features to friendica
'complete' => [
'test',
<<<TEXT
- <?php
/*
* Name: Test Addon
* Description: adds awesome features to friendica
use Exception;
use Friendica\Core\Addon\AddonInfo;
use Friendica\Core\Addon\AddonManagerHelper;
+use Friendica\Core\Addon\Exception\InvalidAddonException;
use Friendica\Core\Cache\Capability\ICanCache;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Database\Database;
$this->assertEquals('Hello Addon', $info->getName());
}
+ public function testGetAddonInfoThrowsInvalidAddonException(): void
+ {
+ $root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [
+ 'helloaddon' => [
+ 'helloaddon.php' => <<<PHP
+ <?php
+ // This is not a valid addon comment section
+ PHP,
+ ]
+ ]);
+
+ $addonManagerHelper = new AddonManagerHelper(
+ $root->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);
{
$root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [
'helloaddon' => [
- 'helloaddon.php' => '<?php',
+ 'helloaddon.php' => <<<PHP
+ <?php
+ /**
+ * Name: Hello Addon
+ * Description: For testing purpose only
+ * Version: 1.0
+ * Author: Artur Weigandt <dont-mail-me@example.com>
+ */
+ 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',