From 36aa0122e15b6c5a4bf923467b63a577cac5a539 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 4 Apr 2023 10:23:26 +0200 Subject: Fix extensions in actualize_script (#5243) * Fix extension freshrss_user_maintenance in actualize_script Follow-up of https://github.com/FreshRSS/FreshRSS/pull/3440 The hook was called before registering all the extensions for the current user * PHPStan Level 6 for extensions And remove 5-year old legacy format of enabled extensions < FreshRSS 1.11.1 * Fix multiple bugs in extensions * Minor typing * Don't change signature of methods supposed to be overridden * PHPStan Level 9 and compatibility Intelliphense * Set as final the methods not supposed to be overriden --- app/Controllers/extensionController.php | 88 ++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 34 deletions(-) (limited to 'app/Controllers/extensionController.php') diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index d1ea889aa..b482b1a35 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -9,7 +9,7 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController { * the common boiler plate for every action. It is triggered by the * underlying framework. */ - public function firstAction() { + public function firstAction(): void { if (!FreshRSS_Auth::hasAccess()) { Minz_Error::error(403); } @@ -18,7 +18,7 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController { /** * This action lists all the extensions available to the current user. */ - public function indexAction() { + public function indexAction(): void { FreshRSS_View::prependTitle(_t('admin.extensions.title') . ' ยท '); $this->view->extension_list = array( 'system' => array(), @@ -33,14 +33,14 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController { $this->view->extensions_installed[$ext->getEntrypoint()] = $ext->getVersion(); } - $availableExtensions = $this->getAvailableExtensionList(); - $this->view->available_extensions = $availableExtensions; + $this->view->available_extensions = $this->getAvailableExtensionList(); } /** * fetch extension list from GitHub + * @return array */ - protected function getAvailableExtensionList() { + protected function getAvailableExtensionList(): array { $extensionListUrl = 'https://raw.githubusercontent.com/FreshRSS/Extensions/master/extensions.json'; $json = @file_get_contents($extensionListUrl); @@ -51,18 +51,17 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController { } // fetch the list as an array + /** @var array */ $list = json_decode($json, true); if (empty($list)) { Minz_Log::warning('Failed to convert extension file list'); return array(); } - // we could use that for comparing and caching later - $version = $list['version']; - // By now, all the needed data is kept in the main extension file. // In the future we could fetch detail information from the extensions metadata.json, but I tend to stick with // the current implementation for now, unless it becomes too much effort maintain the extension list manually + /** @var array */ $extensions = $list['extensions']; return $extensions; @@ -78,22 +77,24 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController { * - additional parameters which should be handle by the extension * handleConfigureAction() method (POST request). */ - public function configureAction() { - if (Minz_Request::param('ajax')) { + public function configureAction(): void { + if (Minz_Request::paramBoolean('ajax')) { $this->view->_layout(false); } else { $this->indexAction(); $this->view->_path('extension/index.phtml'); } - $ext_name = urldecode(Minz_Request::param('e')); + $ext_name = urldecode(Minz_Request::paramString('e')); $ext = Minz_ExtensionManager::findExtension($ext_name); - if (is_null($ext)) { + if ($ext === null) { Minz_Error::error(404); + return; } if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { Minz_Error::error(403); + return; } $this->view->extension = $ext; @@ -109,41 +110,52 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController { * Parameter is: * - e: the extension name (urlencoded). */ - public function enableAction() { + public function enableAction(): void { $url_redirect = array('c' => 'extension', 'a' => 'index'); if (Minz_Request::isPost()) { - $ext_name = urldecode(Minz_Request::param('e')); + $ext_name = urldecode(Minz_Request::paramString('e')); $ext = Minz_ExtensionManager::findExtension($ext_name); if (is_null($ext)) { Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), $url_redirect); + return; } if ($ext->isEnabled()) { Minz_Request::bad(_t('feedback.extensions.already_enabled', $ext_name), $url_redirect); } + $type = $ext->getType(); + if ($type !== 'user' && !FreshRSS_Auth::hasAccess('admin')) { + Minz_Request::bad(_t('feedback.extensions.no_access', $ext_name), $url_redirect); + return; + } + $conf = null; - if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { + if ($type === 'system') { $conf = FreshRSS_Context::$system_conf; - } elseif ($ext->getType() === 'user') { + } elseif ($type === 'user') { $conf = FreshRSS_Context::$user_conf; - } else { - Minz_Request::bad(_t('feedback.extensions.no_access', $ext_name), $url_redirect); } $res = $ext->install(); - if ($res === true) { + if ($conf !== null && $res === true) { $ext_list = $conf->extensions_enabled; + $ext_list = array_filter($ext_list, function($key) use($type) { + // Remove from list the extensions that have disappeared or changed type + $extension = Minz_ExtensionManager::findExtension($key); + return $extension !== null && $extension->getType() === $type; + }, ARRAY_FILTER_USE_KEY); + $ext_list[$ext_name] = true; $conf->extensions_enabled = $ext_list; $conf->save(); Minz_Request::good(_t('feedback.extensions.enable.ok', $ext_name), $url_redirect); } else { - Minz_Log::warning('Can not enable extension ' . $ext_name . ': ' . $res); + Minz_Log::warning('Cannot enable extension ' . $ext_name . ': ' . $res); Minz_Request::bad(_t('feedback.extensions.enable.ko', $ext_name, _url('index', 'logs')), $url_redirect); } } @@ -160,45 +172,52 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController { * Parameter is: * - e: the extension name (urlencoded). */ - public function disableAction() { + public function disableAction(): void { $url_redirect = array('c' => 'extension', 'a' => 'index'); if (Minz_Request::isPost()) { - $ext_name = urldecode(Minz_Request::param('e')); + $ext_name = urldecode(Minz_Request::paramString('e')); $ext = Minz_ExtensionManager::findExtension($ext_name); if (is_null($ext)) { Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), $url_redirect); + return; } if (!$ext->isEnabled()) { Minz_Request::bad(_t('feedback.extensions.not_enabled', $ext_name), $url_redirect); } + $type = $ext->getType(); + if ($type !== 'user' && !FreshRSS_Auth::hasAccess('admin')) { + Minz_Request::bad(_t('feedback.extensions.no_access', $ext_name), $url_redirect); + return; + } + $conf = null; - if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { + if ($type === 'system') { $conf = FreshRSS_Context::$system_conf; - } elseif ($ext->getType() === 'user') { + } elseif ($type === 'user') { $conf = FreshRSS_Context::$user_conf; - } else { - Minz_Request::bad(_t('feedback.extensions.no_access', $ext_name), $url_redirect); } $res = $ext->uninstall(); - if ($res === true) { + if ($conf !== null && $res === true) { $ext_list = $conf->extensions_enabled; - $legacyKey = array_search($ext_name, $ext_list, true); - if ($legacyKey !== false) { //Legacy format FreshRSS < 1.11.1 - unset($ext_list[$legacyKey]); - } + $ext_list = array_filter($ext_list, function($key) use($type) { + // Remove from list the extensions that have disappeared or changed type + $extension = Minz_ExtensionManager::findExtension($key); + return $extension !== null && $extension->getType() === $type; + }, ARRAY_FILTER_USE_KEY); + $ext_list[$ext_name] = false; $conf->extensions_enabled = $ext_list; $conf->save(); Minz_Request::good(_t('feedback.extensions.disable.ok', $ext_name), $url_redirect); } else { - Minz_Log::warning('Can not unable extension ' . $ext_name . ': ' . $res); + Minz_Log::warning('Cannot disable extension ' . $ext_name . ': ' . $res); Minz_Request::bad(_t('feedback.extensions.disable.ko', $ext_name, _url('index', 'logs')), $url_redirect); } } @@ -215,7 +234,7 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController { * Parameter is: * -e: extension name (urlencoded) */ - public function removeAction() { + public function removeAction(): void { if (!FreshRSS_Auth::hasAccess('admin')) { Minz_Error::error(403); } @@ -223,11 +242,12 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController { $url_redirect = array('c' => 'extension', 'a' => 'index'); if (Minz_Request::isPost()) { - $ext_name = urldecode(Minz_Request::param('e')); + $ext_name = urldecode(Minz_Request::paramString('e')); $ext = Minz_ExtensionManager::findExtension($ext_name); if (is_null($ext)) { Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), $url_redirect); + return; } $res = recursive_unlink($ext->getPath()); -- cgit v1.2.3