Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions plugins/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,4 @@ the packaged plugin (`pkg_build.sh` only ships `source/community.applications/`)
- Fixed: On Spotlight app cards, a long application name no longer runs underneath the "Monthly Spotlight" badge
- Changed: Long application names on app cards now wrap to a second line instead of being cut off with an ellipsis
- Removed: The category line on app cards (the category is still shown in the app panel)
- Fixed: Prevented rare Apps page errors and log noise caused by corrupted cache files, malformed application-feed data, or unusual template and settings values; pinned apps now also respect the Hide Deprecated setting
Original file line number Diff line number Diff line change
Expand Up @@ -1968,7 +1968,7 @@ function pinApp() {

$repository = getPost("repository","oops");
$name = getPost("name","oops");
$pinnedApps = readJsonFile(CA_PATHS['pinnedV2']);
$pinnedApps = (array)readJsonFile(CA_PATHS['pinnedV2']);
if (isset($pinnedApps["$repository&$name"]) )
$pinnedApps["$repository&$name"] = false;
else
Expand All @@ -1985,7 +1985,7 @@ function pinApp() {
*/
function areAppsPinned() {

postReturn(['status' => in_array(true,readJsonFile(CA_PATHS['pinnedV2']))]);
postReturn(['status' => in_array(true,(array)readJsonFile(CA_PATHS['pinnedV2']))]);
}

/**
Expand Down Expand Up @@ -2016,13 +2016,14 @@ function pinnedApps() {

$displayed = [];
$hideIncompatible = ($GLOBALS['caSettings']['hideIncompatible'] ?? "false") === "true";
$hideDeprecated = ($GLOBALS['caSettings']['hideDeprecated'] ?? "false") === "true";

foreach ($pinnedApps as $pinned) {
if (!is_string($pinned) || strpos($pinned, '&') === false) {
continue;
}

$template = PinnedAppsHelpers::findPinnedTemplate($templates, $pinned, $hideIncompatible);
$template = PinnedAppsHelpers::findPinnedTemplate($templates, $pinned, $hideIncompatible, $hideDeprecated);
if ($template !== null) {
$displayed[] = $template;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function getGlobals() {
clearstatcache();
if ( is_file(CA_PATHS['community-templates-info']) ) {
if ( ! isset($GLOBALS['templates']) ) {
$GLOBALS['templates'] = readJsonFile(CA_PATHS['community-templates-info']);
$GLOBALS['templates'] = (array)readJsonFile(CA_PATHS['community-templates-info']);
}
} else {
$GLOBALS['templates'] = [];
Expand All @@ -80,7 +80,7 @@ function getGlobals() {
* @return void
*/
function getFullGlobals() {
$GLOBALS['templates'] = readJsonFile(CA_PATHS['community-templates-info-full']);
$GLOBALS['templates'] = (array)readJsonFile(CA_PATHS['community-templates-info-full']);
getSettings();
}

Expand Down Expand Up @@ -1178,7 +1178,12 @@ function makeXML($template) {
}
}
$Array2XML = new Array2XML();
$xml = $Array2XML->createXML("Container",$template);
try {
$xml = $Array2XML->createXML("Container",$template);
} catch (Throwable $e) {
debug("makeXML: Array2XML failed for ".($template['Name'] ?? 'unknown')." - ".$e->getMessage());
return false;
}
Comment thread
Squidly271 marked this conversation as resolved.
return $xml->saveXML();
}
/**
Expand Down Expand Up @@ -1340,6 +1345,7 @@ function moderateTemplates() {
$templates = &$GLOBALS['templates'];

if ( ! $templates ) return;
$o = [];
foreach ($templates as $template) {
$template['Compatible'] = versionCheck($template);
if ( ($template['MaxVer']??null) && version_compare($template['MaxVer'],$GLOBALS['caSettings']['unRaidVersion']) < 0 )
Expand Down Expand Up @@ -1927,6 +1933,12 @@ function postReturn($retArray) {
* @return string
*/
function tr($string,$options=-1) {
// dynamix _() runs trim() on its argument immediately, which TypeErrors
// on an array and deprecation-warns on null under PHP 8. Coerce scalars
// to string and collapse anything else to empty so a stray non-string
// (eg. a malformed feed field) can never fatal in the translator.
if ( ! is_string($string) )
$string = is_scalar($string) ? (string)$string : "";
$translated = _($string,$options);
if ( ! trim($translated) )
$translated = $string;
Expand Down Expand Up @@ -1967,7 +1979,7 @@ function languageCheck($template) {
$xmlFile = readXmlFile($installedLanguage,true);

if ( !$xmlFile['Version'] ) return false;
return (strcmp($template['Version'],$xmlFile['Version']) > 0) || (strcmp($OSupdates['Version'],$xmlFile['Version']) > 0);
return (strcmp((string)($template['Version'] ?? ''),$xmlFile['Version']) > 0) || (strcmp($OSupdates['Version'],$xmlFile['Version']) > 0);
}
/**
* Serialize an associative array (with optional one-level sections) to INI on disk.
Expand Down Expand Up @@ -2037,7 +2049,10 @@ function getAllInfo($force=false) {
} else {
debug("Cached info update");
}
return $containers;
// Cast so a corrupt CA_PATHS['info'] cache that readJsonFile decodes to a
// scalar can never reach the typed array $info params downstream (which
// would TypeError). Consumers always get an array, empty at worst.
return (array)$containers;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static function clearPinnedCacheFiles($cacheKeys) {
* @param bool $hideIncompatible When true, skip templates that aren't compatible.
* @return array<string,mixed>|null Matching template, or null when nothing matches.
*/
public static function findPinnedTemplate(&$templates, $pinned, $hideIncompatible) {
public static function findPinnedTemplate(&$templates, $pinned, $hideIncompatible, $hideDeprecated = false) {
$search = explode("&", $pinned);
if (count($search) < 2) {
return null;
Expand Down Expand Up @@ -67,6 +67,11 @@ public static function findPinnedTemplate(&$templates, $pinned, $hideIncompatibl
continue;
}

if ($hideDeprecated && !empty($template['Deprecated'])) {
$startIndex = $index + 1;
continue;
}

return $template;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -585,8 +585,11 @@ public static function init($version = '1.0', $encoding = 'UTF-8', $format_outpu
*/
public static function &createXML($node_name, $arr=array()) {
$xml = self::getXMLRoot();
$xml->appendChild(self::convert($node_name, $arr));
self::$xml = null; // clear the xml node in the class for 2nd time use.
try {
$xml->appendChild(self::convert($node_name, $arr));
} finally {
self::$xml = null; // clear the xml node in the class for 2nd time use, even on throw.
}
return $xml;
}
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,7 @@ function my_display_apps($file,$pageNumber=1,$selectedApps=false,$startup=false,
$repositories = readJsonFile(CA_PATHS['repositoryList']);
$extraBlacklist = readJsonFile(CA_PATHS['extraBlacklist']);
$extraDeprecated = readJsonFile(CA_PATHS['extraDeprecated']);
$pinnedApps = readJsonFile(CA_PATHS['pinnedV2']);
$pinnedApps = (array)readJsonFile(CA_PATHS['pinnedV2']);

$ct = "";
$cardsArray = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,11 +565,11 @@ function caBuildActionsContext(array &$template, array $info, array $dockerUpdat
$actionsContext[] = ["icon"=>"ca_fa-install","text"=>tr("Install second"),"action"=>"popupInstallXML('".addslashes($template['Path'])."','second');"];
}
}
if (is_file($info[$name]['template'])) {
if (is_file($info[$name]['template'] ?? "")) {
$actionsContext[] = ["icon"=>"ca_fa-edit","text"=>tr("Edit"),"action"=>"popupInstallXML('".addslashes($info[$name]['template'])."','edit');"];
}
$actionsContext[] = ["divider"=>true];
if ($info[$name]['template']) {
if ($info[$name]['template'] ?? false) {
$actionsContext[] = ["icon"=>"ca_fa-delete","text"=>tr("Uninstall"),"action"=>"uninstallDocker('".addslashes($info[$name]['template'])."','{$template['Name']}');"];
$template['Installed'] = true;
}
Expand Down Expand Up @@ -727,7 +727,7 @@ function caBuildLanguageActions(array &$template, ?string $countryCode, array $a
$actionsContext[] = ["icon"=>"ca_fa-switchto","text"=>$template['SwitchLanguage'],"action"=>"CAswitchLanguage('$countryCode');"];
}
} else {
$actionsContext[] = ["icon"=>"ca_fa-install","text"=>tr("Install"),"action"=>"installLanguage('{$template['TemplateURL']}','$countryCode');"];
$actionsContext[] = ["icon"=>"ca_fa-install","text"=>tr("Install"),"action"=>"installLanguage('".($template['TemplateURL'] ?? '')."','$countryCode');"];
}

if (file_exists("/var/log/plugins/lang-$countryCode.xml")) {
Expand Down Expand Up @@ -909,7 +909,7 @@ function caProcessDockerTemplate(array $template, array $info, array $dockerUpda
$template['Installed'] = $selected;
if ($selected) {
$ind = searchArray($info, "Name", $name);
if ($info[$ind]['url'] && $info[$ind]['running']) {
if ($ind !== false && ($info[$ind]['url'] ?? false) && ($info[$ind]['running'] ?? false)) {
$actionsContext[] = ["icon" => "ca_fa-globe", "text" => tr("WebUI"), "action" => "openNewWindow('{$info[$ind]['url']}','_blank');"];
if ($info[$ind]['TSurl'] ?? false) {
$actionsContext[] = ["icon" => "ca_fa-globe", "text" => tr("TS WebUI"), "action" => "openNewWindow('{$info[$ind]['TSurl']}','_blank');"];
Expand Down Expand Up @@ -941,12 +941,12 @@ function caProcessDockerTemplate(array $template, array $info, array $dockerUpda
}
}

if (is_file($info[$ind]['template'])) {
if ($ind !== false && is_file($info[$ind]['template'] ?? "")) {
$actionsContext[] = ["icon" => "ca_fa-edit", "text" => tr("Edit"), "action" => "popupInstallXML('".addslashes($info[$ind]['template'])."','edit');"];
}

$actionsContext[] = ["divider" => true];
if ($info[$ind]['template']) {
if ($ind !== false && ($info[$ind]['template'] ?? false)) {
$actionsContext[] = ["icon" => "ca_fa-delete", "text" => tr("Uninstall"), "action" => "uninstallDocker('".addslashes($info[$ind]['template'])."','{$template['Name']}');"];
}
} elseif (! ($template['Blacklist'] ?? false)) {
Expand Down Expand Up @@ -1127,7 +1127,7 @@ function caProcessLanguageTemplate(array $template, array $actionsContext): arra
$actionsContext[] = ["icon" => "ca_fa-switchto", "text" => $template['SwitchLanguage'], "action" => "CAswitchLanguage('$countryCode');"];
}
} else {
$actionsContext[] = ["icon" => "ca_fa-install", "text" => tr("Install"), "action" => "installLanguage('{$template['TemplateURL']}','$countryCode');"];
$actionsContext[] = ["icon" => "ca_fa-install", "text" => tr("Install"), "action" => "installLanguage('".($template['TemplateURL'] ?? '')."','$countryCode');"];
}

if (file_exists("/var/log/plugins/lang-$countryCode.xml")) {
Expand Down
Loading