diff --git a/core/ajax/plugin.ajax.php b/core/ajax/plugin.ajax.php
index 909cc46060..a6face2566 100644
--- a/core/ajax/plugin.ajax.php
+++ b/core/ajax/plugin.ajax.php
@@ -30,7 +30,7 @@
if (!isConnect('admin')) {
throw new Exception(__('401 - Accès non autorisé', __FILE__));
}
- $plugin = plugin::byId(init('id'));
+ $plugin = plugin::byId(init('id'),init('full',0));
$update = update::byLogicalId(init('id'));
$return = utils::o2a($plugin);
$return['activate'] = $plugin->isActive();
diff --git a/core/api/jeeApi.php b/core/api/jeeApi.php
index 59f9db54b4..0ebce9bd61 100644
--- a/core/api/jeeApi.php
+++ b/core/api/jeeApi.php
@@ -33,8 +33,11 @@
/** @var bool $_RESTRICTED */
global $_RESTRICTED;
$_RESTRICTED = false;
+
+
if (init('type') != '') {
try {
+
if (init('type') == 'ask') {
if (trim(init('token')) == '' || strlen(init('token')) < 64) {
throw new Exception(__('Commande inconnue ou Token invalide', __FILE__));
@@ -60,6 +63,13 @@
sleep(5);
throw new Exception(__('Vous n\'êtes pas autorisé à effectuer cette action, IP :', __FILE__) . ' ' . getClientIp());
}
+
+ if(config::byKey('api::forbidden::method', 'core', '') !== '' && preg_match(config::byKey('api::forbidden::method', 'core', ''), init('type'))){
+ throw new Exception(__('Cette demande n\'est autorisée', __FILE__) . ' ' . getClientIp());
+ }
+ if(config::byKey('api::allow::method', 'core', '') !== '' && !preg_match(config::byKey('api::allow::method', 'core', ''), init('type'))){
+ throw new Exception(__('Cette demande n\'est autorisée', __FILE__) . ' ' . getClientIp());
+ }
$type = init('type');
log::add('api', 'debug', __('Demande sur l\'api http venant de :', __FILE__) . ' ' . getClientIp() . ' => ' . json_encode($_GET));
@@ -225,7 +235,7 @@
if ($type == 'fullData') {
log::add('api', 'debug', __('Demande API pour les commandes', __FILE__));
header('Content-Type: application/json');
- echo json_encode(jeeObject::fullData(), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE, 1024);
+ echo json_encode(jeeObject::fullData(null,$_USER_GLOBAL), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE, 1024);
die();
}
if ($type == 'variable') {
@@ -269,6 +279,13 @@
throw new Exception(__('Requête invalide. Version JSON-RPC invalide :', __FILE__) . ' ' . $jsonrpc->getJsonrpc(), -32001);
}
+ if(config::byKey('api::forbidden::method', 'core', '') !== '' && preg_match(config::byKey('api::forbidden::method', 'core', ''), $jsonrpc->getMethod())){
+ throw new Exception(__('Cette demande n\'est autorisée', __FILE__));
+ }
+ if(config::byKey('api::allow::method', 'core', '') !== '' && !preg_match(config::byKey('api::allow::method', 'core', ''), $jsonrpc->getMethod())){
+ throw new Exception(__('Cette demande n\'est autorisée', __FILE__) . ' ' . getClientIp());
+ }
+
$params = $jsonrpc->getParams();
if (!isset($params['plugin']) || $params['plugin'] == '') {
diff --git a/core/class/DB.class.php b/core/class/DB.class.php
index 4cd5a96487..ca3b48db09 100644
--- a/core/class/DB.class.php
+++ b/core/class/DB.class.php
@@ -91,6 +91,15 @@ public static function &Prepare($_query, $_params, $_fetchType = self::FETCH_TYP
$stmt = static::getConnection()->prepare($_query);
$res = NULL;
if ($stmt != false && $stmt->execute($_params) != false) {
+ if(preg_match('/^update|^replace|^delete|^create|^drop|^alter|^truncate/i', $_query)){
+ $errorInfo = $stmt->errorInfo();
+ if ($errorInfo[0] != 0000) {
+ static::$lastConnection = 0;
+ throw new Exception('[MySQL] Error code : ' . $errorInfo[0] . ' (' . $errorInfo[1] . '). ' . $errorInfo[2] . ' : ' . $_query);
+ }
+ static::$lastConnection = strtotime('now');
+ return $res;
+ }
if ($_fetchType == static::FETCH_TYPE_ROW) {
if ($_fetch_opt === null) {
$res = $stmt->fetch($_fetch_param);
diff --git a/core/class/cache.class.php b/core/class/cache.class.php
index 0b594b0f85..857085a47e 100644
--- a/core/class/cache.class.php
+++ b/core/class/cache.class.php
@@ -96,46 +96,60 @@ public static function stats($_details = false) {
* @name getCache()
* @access public
* @static
+ * @param string $_engine to override the current cache defined in configuration
* @return \Doctrine\Common\Cache\CacheProvider
*/
- public static function getCache() {
- if (self::$cache !== null) {
+ public static function getCache($_engine = null) {
+ if ($_engine === null && self::$cache !== null) {
return self::$cache;
}
- $engine = config::byKey('cache::engine');
- if ($engine == 'MemcachedCache' && !class_exists('memcached')) {
- $engine = 'FilesystemCache';
- config::save('cache::engine', 'FilesystemCache');
- }
- if ($engine == 'RedisCache' && !class_exists('redis')) {
- $engine = 'FilesystemCache';
- config::save('cache::engine', 'FilesystemCache');
+ if( $_engine === null){
+ // get current cache
+ $engine = config::byKey('cache::engine');
+ }else{
+ // override existing configuration
+ $engine = $_engine;
+ config::save('cache::engine', $_engine);
}
switch ($engine) {
- case 'FilesystemCache':
- self::$cache = new \Doctrine\Common\Cache\FilesystemCache(self::getFolder());
- break;
case 'PhpFileCache':
self::$cache = new \Doctrine\Common\Cache\FilesystemCache(self::getFolder());
break;
case 'MemcachedCache':
+ // check if memcached extention is available
+ if (!class_exists('memcached')) {
+ log::add( __CLASS__, 'error', 'memcached extension not installed, fall back to FilesystemCache.');
+ return self::getCache( 'FilesystemCache');
+ }
$memcached = new Memcached();
$memcached->addServer(config::byKey('cache::memcacheaddr'), config::byKey('cache::memcacheport'));
self::$cache = new \Doctrine\Common\Cache\MemcachedCache();
self::$cache->setMemcached($memcached);
break;
case 'RedisCache':
+ // check if redis extension is available
+ if (!class_exists('redis')) {
+ log::add( __CLASS__, 'error', 'redis extension not installed, fall back to FilesystemCache.');
+ return self::getCache( 'FilesystemCache');
+ }
$redis = new Redis();
$redisAddr = config::byKey('cache::redisaddr');
- if (strncmp($redisAddr, '/', 1) === 0) {
- $redis->connect($redisAddr);
- } else {
- $redis->connect($redisAddr, config::byKey('cache::redisport'));
+ try{
+ // try to connect to redis
+ if (strncmp($redisAddr, '/', 1) === 0) {
+ $redis->connect($redisAddr);
+ } else {
+ $redis->connect($redisAddr, config::byKey('cache::redisport'));
+ }
+ }catch( Exception $e){
+ // error : fall back to FilesystemCache
+ log::add( __CLASS__, 'error', 'Unable to connect to redis instance, fall back to FilesystemCache.'."\n".$e->getMessage());
+ return self::getCache( 'FilesystemCache');
}
self::$cache = new \Doctrine\Common\Cache\RedisCache();
self::$cache->setRedis($redis);
break;
- default:
+ default: // default is FilesystemCache
self::$cache = new \Doctrine\Common\Cache\FilesystemCache(self::getFolder());
break;
}
diff --git a/core/class/cmd.class.php b/core/class/cmd.class.php
index f2e983a3a8..f83148b77a 100644
--- a/core/class/cmd.class.php
+++ b/core/class/cmd.class.php
@@ -1658,7 +1658,7 @@ public function toHtml($_version = 'dashboard', $_options = '') {
$coupleArray = explode('|', $element);
$cmdValue = $this->getCmdValue();
if (is_object($cmdValue) && $cmdValue->getType() == 'info') {
- if ($cmdValue->execCmd() == $coupleArray[0]) {
+ if ($cmdValue->execCmd() == $coupleArray[0] || $cmdValue->execCmd() == $coupleArray[1]) {
$listOption .= '';
$foundSelect = true;
} else {
diff --git a/core/class/cron.class.php b/core/class/cron.class.php
index 643604072c..12c415670f 100644
--- a/core/class/cron.class.php
+++ b/core/class/cron.class.php
@@ -372,6 +372,10 @@ public function isDue() {
return false;
}
try {
+ $schedule = explode(' ',$this->getSchedule());
+ if(count($schedule) == 6 && $schedule[5] != strtotime('Y')){
+ return false;
+ }
$c = new Cron\CronExpression(checkAndFixCron($this->getSchedule()), new Cron\FieldFactory);
try {
if ($c->isDue()) {
@@ -551,7 +555,7 @@ public function setDeamonSleepTime($_deamonSleepTime) {
}
public function getOption() {
- return json_decode($this->option, true);
+ return json_decode($this->option ?? '', true);
}
public function getOnce($_default = 0) {
diff --git a/core/class/eqLogic.class.php b/core/class/eqLogic.class.php
index 8b14b22a1a..272a8306be 100644
--- a/core/class/eqLogic.class.php
+++ b/core/class/eqLogic.class.php
@@ -494,6 +494,9 @@ public static function toHumanReadable($_input) {
}
public static function fromHumanReadable($_input) {
+ if(empty($_input)){
+ return $_input;
+ }
$isJson = false;
if (is_json($_input)) {
$isJson = true;
@@ -525,7 +528,7 @@ public static function fromHumanReadable($_input) {
return $_input;
}
$text = $_input;
- preg_match_all("/#\[(.*?)\]\[(.*?)\]#/", $text, $matches);
+ preg_match_all( "/#\[(.*?)\]\[(.*?)\]#/", $text, $matches);
if (count($matches) == 3) {
$countMatches = count($matches[0]);
for ($i = 0; $i < $countMatches; $i++) {
diff --git a/core/class/history.class.php b/core/class/history.class.php
index c1ed749631..d0f5de4a99 100644
--- a/core/class/history.class.php
+++ b/core/class/history.class.php
@@ -1010,7 +1010,7 @@ public function save($_cmd = null, $_direct = false) {
if ($this->getValue() === null) {
return;
}
- //global $JEEDOM_INTERNAL_CONFIG;
+ global $JEEDOM_INTERNAL_CONFIG;
if ($_cmd === null) {
$cmd = $this->getCmd();
if (!is_object($cmd)) {
diff --git a/core/class/jeeObject.class.php b/core/class/jeeObject.class.php
index efb641ad12..37775f9722 100644
--- a/core/class/jeeObject.class.php
+++ b/core/class/jeeObject.class.php
@@ -147,6 +147,9 @@ public static function toHumanReadable($_input) {
}
public static function fromHumanReadable($_input) {
+ if(empty($_input)){
+ return $_input;
+ }
$isJson = false;
if (is_json($_input)) {
$isJson = true;
diff --git a/core/class/jeedom.class.php b/core/class/jeedom.class.php
index b3bfd2bf1e..2e280b282c 100644
--- a/core/class/jeedom.class.php
+++ b/core/class/jeedom.class.php
@@ -190,18 +190,19 @@ public static function health() {
'comment' => '',
'key' => 'uptodate'
);
-
- $status = shell_exec('systemctl status fail2ban.service');
- $failed = stripos($status, 'failed') !== false;
- $running = stripos($status, 'running') !== false;
- $state = $failed ? 0 : ($running ? 1 : 2);
- $return[] = array(
- 'name' => __('Etat du service fail2ban', __FILE__),
- 'state' => $failed ? 0 : ($running ? 1 : 2),
- 'result' => $failed ? __('En échec', __FILE__) : ($running ? __('Actif', __FILE__) : __('Désactivé', __FILE__)),
- 'comment' => ($failed || !$running) ? __("Le service Linux fail2ban est désactivé ou en échec : les tentatives d'accès infructueuses à Jeedom ne résulteront pas en un bannissement des IP concernées. Vérifiez l'état du service si vous souhaitez réactiver fail2ban.", __FILE__) : '',
- 'key' => 'service::fail2ban'
- );
+ if (version_compare(self::getOsVersion(), '12', '<')) {
+ $status = shell_exec('systemctl status fail2ban.service');
+ $failed = stripos($status, 'failed') !== false;
+ $running = stripos($status, 'running') !== false;
+ $state = $failed ? 0 : ($running ? 1 : 2);
+ $return[] = array(
+ 'name' => __('Etat du service fail2ban', __FILE__),
+ 'state' => $failed ? 0 : ($running ? 1 : 2),
+ 'result' => $failed ? __('En échec', __FILE__) : ($running ? __('Actif', __FILE__) : __('Désactivé', __FILE__)),
+ 'comment' => ($failed || !$running) ? __("Le service Linux fail2ban est désactivé ou en échec : les tentatives d'accès infructueuses à Jeedom ne résulteront pas en un bannissement des IP concernées. Vérifiez l'état du service si vous souhaitez réactiver fail2ban.", __FILE__) : '',
+ 'key' => 'service::fail2ban'
+ );
+ }
$state = (config::byKey('enableCron', 'core', 1, true) != 0) ? true : false;
$return[] = array(
@@ -459,7 +460,7 @@ public static function health() {
);
if (shell_exec('which python') != '') {
- $value = shell_exec('python --version');
+ $value = shell_exec('python --version 2>&1'); // prior python 3.4, 'python --version' output was on stderr
$return[] = array(
'name' => __('Python', __FILE__),
'state' => true,
diff --git a/core/class/jsonrpcClient.class.php b/core/class/jsonrpcClient.class.php
index f388d24b11..5a00138230 100644
--- a/core/class/jsonrpcClient.class.php
+++ b/core/class/jsonrpcClient.class.php
@@ -175,7 +175,7 @@ private function send($_request, $_timeout = 15, $_file = null, $_maxRetry = 2)
if (curl_errno($ch)) {
$this->error = 'Erreur curl sur : ' . $this->apiAddr . '. Détail :' . curl_error($ch);
}
- curl_close($ch);
+ unset($ch);
return $response;
}
diff --git a/core/class/network.class.php b/core/class/network.class.php
index 7cd4136309..0573c82b32 100644
--- a/core/class/network.class.php
+++ b/core/class/network.class.php
@@ -275,7 +275,7 @@ public static function test($_mode = 'external', $_timeout = 15) {
return false;
}
}
- curl_close($ch);
+ unset($ch);
if (trim($data) != 'ok') {
log::add('network', 'debug', 'Retour NOK sur ' . $url . ' => ' . $data);
return false;
diff --git a/core/class/plugin.class.php b/core/class/plugin.class.php
index 575559014b..7cc8b10386 100644
--- a/core/class/plugin.class.php
+++ b/core/class/plugin.class.php
@@ -57,10 +57,10 @@ class plugin {
/* * ***********************Méthodes statiques*************************** */
- public static function byId($_id) {
+ public static function byId($_id,$_full = false) {
global $JEEDOM_INTERNAL_CONFIG;
- if (is_string($_id) && isset(self::$_cache[$_id])) {
- return self::$_cache[$_id];
+ if (is_string($_id) && isset(self::$_cache[$_id.'::'.$_full])) {
+ return self::$_cache[$_id.'::'.$_full];
}
if (!file_exists($_id) || strpos($_id, '/') === false) {
$path = self::getPathById($_id);
@@ -109,7 +109,6 @@ public static function byId($_id) {
$plugin->changelog_beta = (isset($data['changelog_beta'])) ? str_replace('#language#', config::byKey('language', 'core', 'fr_FR'), $data['changelog_beta']) : '';
$plugin->documentation_beta = (isset($data['documentation_beta'])) ? str_replace('#language#', config::byKey('language', 'core', 'fr_FR'), $data['documentation_beta']) : '';
if (isset($data['specialAttributes'])) {
-
if (isset($data['specialAttributes']['object'])) {
$plugin->specialAttributes['object'] = $data['specialAttributes']['object'];
}
@@ -132,16 +131,22 @@ public static function byId($_id) {
'type' => 'class',
);
}
- $plugin->functionality['interact'] = array('exists' => method_exists($plugin->getId(), 'interact'), 'controlable' => 1);
- $plugin->functionality['cron'] = array('exists' => method_exists($plugin->getId(), 'cron'), 'controlable' => 1);
- $plugin->functionality['cron5'] = array('exists' => method_exists($plugin->getId(), 'cron5'), 'controlable' => 1);
- $plugin->functionality['cron10'] = array('exists' => method_exists($plugin->getId(), 'cron10'), 'controlable' => 1);
- $plugin->functionality['cron15'] = array('exists' => method_exists($plugin->getId(), 'cron15'), 'controlable' => 1);
- $plugin->functionality['cron30'] = array('exists' => method_exists($plugin->getId(), 'cron30'), 'controlable' => 1);
- $plugin->functionality['cronHourly'] = array('exists' => method_exists($plugin->getId(), 'cronHourly'), 'controlable' => 1);
- $plugin->functionality['cronDaily'] = array('exists' => method_exists($plugin->getId(), 'cronDaily'), 'controlable' => 1);
- $plugin->functionality['deadcmd'] = array('exists' => method_exists($plugin->getId(), 'deadCmd'), 'controlable' => 0);
- $plugin->functionality['health'] = array('exists' => method_exists($plugin->getId(), 'health'), 'controlable' => 0);
+ if($_full){
+ $plugin->functionality['interact'] = array('exists' => method_exists($plugin->getId(), 'interact'), 'controlable' => 1);
+ $plugin->functionality['cron'] = array('exists' => method_exists($plugin->getId(), 'cron'), 'controlable' => 1);
+ $plugin->functionality['cron5'] = array('exists' => method_exists($plugin->getId(), 'cron5'), 'controlable' => 1);
+ $plugin->functionality['cron10'] = array('exists' => method_exists($plugin->getId(), 'cron10'), 'controlable' => 1);
+ $plugin->functionality['cron15'] = array('exists' => method_exists($plugin->getId(), 'cron15'), 'controlable' => 1);
+ $plugin->functionality['cron30'] = array('exists' => method_exists($plugin->getId(), 'cron30'), 'controlable' => 1);
+ $plugin->functionality['cronHourly'] = array('exists' => method_exists($plugin->getId(), 'cronHourly'), 'controlable' => 1);
+ $plugin->functionality['cronDaily'] = array('exists' => method_exists($plugin->getId(), 'cronDaily'), 'controlable' => 1);
+ $plugin->functionality['deadcmd'] = array('exists' => method_exists($plugin->getId(), 'deadCmd'), 'controlable' => 0);
+ $plugin->functionality['health'] = array('exists' => method_exists($plugin->getId(), 'health'), 'controlable' => 0);
+ if($plugin->getCache('usedSpace',-1) == -1){
+ $plugin->setCache('usedSpace',getDirectorySize(__DIR__ . '/../../plugins/' . $data['id']),86400);
+ }
+ $plugin->usedSpace = $plugin->getCache('usedSpace',-1);
+ }
if (!isset($JEEDOM_INTERNAL_CONFIG['plugin']['category'][$plugin->category])) {
foreach ($JEEDOM_INTERNAL_CONFIG['plugin']['category'] as $key => $value) {
if (!isset($value['alias'])) {
@@ -153,8 +158,7 @@ public static function byId($_id) {
}
}
}
- $plugin->usedSpace = getDirectorySize(__DIR__ . '/../../plugins/' . $data['id']);
- self::$_cache[$plugin->id] = $plugin;
+ self::$_cache[$plugin->id.'::'.$_full] = $plugin;
return $plugin;
}
@@ -1332,4 +1336,13 @@ public function setWhiteListFolders($paths) {
$this->whiteListFolders = (array) $paths;
return $this;
}
+
+ public function getCache($_key = '', $_default = '') {
+ $cache = cache::byKey('pluginCacheAttr' . $this->getId())->getValue();
+ return utils::getJsonAttr($cache, $_key, $_default);
+ }
+
+ public function setCache($_key, $_value = null, $_lifetime = 0) {
+ cache::set('pluginCacheAttr' . $this->getId(), utils::setJsonAttr(cache::byKey('pluginCacheAttr' . $this->getId())->getValue(), $_key, $_value), $_lifetime);
+ }
}
diff --git a/core/class/scenario.class.php b/core/class/scenario.class.php
index a579549236..20f58ed5c3 100644
--- a/core/class/scenario.class.php
+++ b/core/class/scenario.class.php
@@ -660,6 +660,9 @@ public static function toHumanReadable($_input) {
* @return string|object|array return value will depends on $_input received
*/
public static function fromHumanReadable($_input) {
+ if(empty($_input)){
+ return $_input;
+ }
$isJson = false;
if (is_json($_input)) {
$isJson = true;
@@ -1191,6 +1194,12 @@ public function calculateScheduleDate() {
$c = new Cron\CronExpression(checkAndFixCron($schedule), new Cron\FieldFactory);
$calculatedDate_tmp['prevDate'] = $c->getPreviousRunDate()->format('Y-m-d H:i:s');
$calculatedDate_tmp['nextDate'] = $c->getNextRunDate()->format('Y-m-d H:i:s');
+ if(count($schedule) == 6 && $schedule[5] != $c->getPreviousRunDate()->format('Y')){
+ $calculatedDate['prevDate'] = '';
+ }
+ if(count($schedule) == 6 && $schedule[5] != $c->getNextRunDate()->format('Y')){
+ $calculatedDate['nextDate'] = '';
+ }
} catch (Exception $exc) {
} catch (Error $exc) {
}
@@ -1206,10 +1215,18 @@ public function calculateScheduleDate() {
$c = new Cron\CronExpression(checkAndFixCron($this->getSchedule()), new Cron\FieldFactory);
$calculatedDate['prevDate'] = $c->getPreviousRunDate()->format('Y-m-d H:i:s');
$calculatedDate['nextDate'] = $c->getNextRunDate()->format('Y-m-d H:i:s');
+ $schedule = explode(' ',$this->getSchedule());
+ if(count($schedule) == 6 && $schedule[5] != $c->getPreviousRunDate()->format('Y')){
+ $calculatedDate['prevDate'] = '';
+ }
+ if(count($schedule) == 6 && $schedule[5] != $c->getNextRunDate()->format('Y')){
+ $calculatedDate['nextDate'] = '';
+ }
} catch (Exception $exc) {
} catch (Error $exc) {
}
}
+
return $calculatedDate;
}
/**
@@ -1230,6 +1247,10 @@ public function isDue() {
if (is_array($this->getSchedule())) {
foreach (($this->getSchedule()) as $schedule) {
try {
+ $schedule = explode(' ',$this->getSchedule());
+ if(count($schedule) == 6 && $schedule[5] != strtotime('Y')){
+ return false;
+ }
$c = new Cron\CronExpression(checkAndFixCron($schedule), new Cron\FieldFactory);
try {
if ($c->isDue()) {
diff --git a/core/class/system.class.php b/core/class/system.class.php
index 96e614a299..58d508bad1 100644
--- a/core/class/system.class.php
+++ b/core/class/system.class.php
@@ -54,7 +54,7 @@ public static function getDistrib() {
return 'custom';
}
if (self::$_distrib === null) {
- self::$_distrib = trim(shell_exec('grep CPE_NAME /etc/os-release | cut -d \'"\' -f 2 | cut -d : -f 3 '));
+ self::$_distrib = trim(shell_exec('grep CPE_NAME /etc/os-release | cut -d \'"\' -f 2 | cut -d : -f 3 ') ?? '');
if (self::$_distrib == '') {
self::$_distrib = trim(shell_exec('grep -e "^ID" /etc/os-release | cut -d \'=\' -f 2'));
}
@@ -94,6 +94,8 @@ public static function getCmdSudo(): string {
}
public static function fuserk($_port, $_protocol = 'tcp'): void {
+ if (!is_string($_port)) return;
+
if (file_exists($_port)) {
exec(system::getCmdSudo() . 'fuser -k ' . $_port . ' > /dev/null 2>&1');
} else {
@@ -379,6 +381,13 @@ public static function getInstallPackage($_type, $_plugin) {
break;
case 'pip3':
$datas = json_decode(shell_exec(self::getCmdSudo() . self::getCmdPython3($_plugin) . ' -m pip list --format=json 2>/dev/null'), true);
+ if (!is_array($datas)) {
+ // patch mainly for debian 11 because python3-gpg is on version '1.14.0-unknown' and pip>24.1 raise error with non-standard version format
+ // no check on os version in case this issue occurs also with debian 12 (hopefully not)
+ // the awk command transforms the output of 'pip list' (multiline columns) to a "json string" to reproduce the result of '--format=json' argument
+ $listToJson = self::getCmdSudo() . self::getCmdPython3($_plugin) . ' -m pip list 2>/dev/null | awk \'BEGIN{print "["} NR>2 {printf "%s{\"name\": \"%s\", \"version\": \"%s\"}",sep,$1,$2; sep=", "} END{print "]\n"}\' ORS=\'\'';
+ $datas = json_decode(shell_exec($listToJson), true);
+ }
if (!is_array($datas)) {
break;
}
@@ -419,7 +428,7 @@ public static function getInstallPackage($_type, $_plugin) {
}
break;
case 'composer':
- $datas = json_decode(shell_exec(self::getCmdSudo() . ' composer show -f json 2>/dev/null'));
+ $datas = json_decode(shell_exec(self::getCmdSudo() . ' composer show -f json 2>/dev/null'), true);
foreach ($datas['installed'] as $value) {
self::$_installPackage[$type_key][mb_strtolower($value['name'])] = array('version' => $value['version']);
}
@@ -467,7 +476,7 @@ public static function checkAndInstall($_packages, $_fix = false, $_foreground =
if (file_exists(__DIR__ . '/../../' . $package . '/package.json')) {
$version = json_decode(file_get_contents(__DIR__ . '/../../' . $package . '/package.json'), true)['version'];
if ($type == 'npm') {
- if (file_exists(__DIR__ . '/../../' . $package . '/node_modules')) {
+ if (file_exists(__DIR__ . '/../../' . $package . '/node_modules') && isset(scandir(__DIR__ . '/../../' . $package . '/node_modules', SCANDIR_SORT_NONE)[2])) {
exec('cd ' . __DIR__ . '/../../' . $package . ';' . self::getCmdSudo() . ' npm ls', $output, $return_var);
if ($return_var == 0) {
$found = 1;
diff --git a/core/class/update.class.php b/core/class/update.class.php
index 8067db4cb2..eb0fc78652 100644
--- a/core/class/update.class.php
+++ b/core/class/update.class.php
@@ -483,6 +483,7 @@ public function postInstallUpdate($_infos) {
if (is_object($plugin) && $plugin->isActive()) {
$plugin->setIsEnable(1);
}
+ $plugin->setCache('usedSpace',null);
break;
}
if (isset($_infos['localVersion'])) {
diff --git a/core/class/user.class.php b/core/class/user.class.php
index 9026002c89..670019cb7a 100644
--- a/core/class/user.class.php
+++ b/core/class/user.class.php
@@ -327,8 +327,8 @@ public static function isBan(): bool {
$values[] = array('datetime' => strtotime('now'), 'ip' => getClientIp());
$_SESSION['failed_count'] = 0;
$_SESSION['failed_datetime'] = -1;
- @session_write_close();
}
+ @session_write_close();
cache::set('security::banip', json_encode($values));
if (!is_array($values)) {
$values = array();
diff --git a/core/class/utils.class.php b/core/class/utils.class.php
index dadef62f97..43389dc37f 100644
--- a/core/class/utils.class.php
+++ b/core/class/utils.class.php
@@ -174,7 +174,7 @@ public static function getJsonAttr(&$_attr, $_key = '', $_default = '') {
if ($_key == '') {
return is_json($_attr, array());
}
- if ($_attr === '') {
+ if (empty($_attr)) {
if (is_array($_key)) {
foreach ($_key as $key) {
$return[$key] = $_default;
@@ -226,7 +226,7 @@ public static function encrypt($plaintext, $password = null) {
}
public static function decrypt($ciphertext, $password = null) {
- if ($ciphertext === '') {
+ if (empty($ciphertext)) {
return null;
}
if ($password == null) {
diff --git a/core/com/http.com.php b/core/com/http.com.php
index 46a33f5164..8f174ab6f0 100644
--- a/core/com/http.com.php
+++ b/core/com/http.com.php
@@ -128,7 +128,7 @@ public function exec($_timeout = 2, $_maxRetry = 3) {
if (!isset($response)) {
$response = '';
}
- if (isset($ch) && is_resource($ch)) {
+ if (isset($ch) && $ch !== false) {
if (curl_errno($ch)) {
$curl_error = curl_error($ch);
curl_close($ch);
@@ -142,7 +142,7 @@ public function exec($_timeout = 2, $_maxRetry = 3) {
throw new Exception(__('Echec de la requête HTTP :', __FILE__) . ' ' . $this->url . ' cURL error : ' . $curl_error, 404);
}
} else {
- curl_close($ch);
+ unset($ch);
}
}
$ch = null;
diff --git a/core/config/version b/core/config/version
index 3401474547..bc30b06460 100644
--- a/core/config/version
+++ b/core/config/version
@@ -1 +1 @@
-4.4.7
\ No newline at end of file
+4.4.8
\ No newline at end of file
diff --git a/core/dom/dom.ui.js b/core/dom/dom.ui.js
index 44ae6a101b..343994b4e4 100644
--- a/core/dom/dom.ui.js
+++ b/core/dom/dom.ui.js
@@ -77,7 +77,20 @@ NodeList.prototype.unseen = function() {
}
return this
}
-
+Element.prototype.toggle = function() {
+ if (this.offsetParent === null){
+ this.style.display = ''
+ } else {
+ this.style.display = 'none'
+ }
+ return this
+}
+NodeList.prototype.toggle = function() {
+ for (var idx = 0; idx < this.length; idx++) {
+ this[idx].toggle()
+ }
+ return this
+}
Element.prototype.empty = function() {
while (this.firstChild) {
this.removeChild(this.lastChild)
diff --git a/core/js/plugin.class.js b/core/js/plugin.class.js
index 236204d9e9..7a17f656fe 100644
--- a/core/js/plugin.class.js
+++ b/core/js/plugin.class.js
@@ -79,7 +79,8 @@ jeedom.plugin.get = function (_params) {
paramsAJAX.url = 'core/ajax/plugin.ajax.php';
paramsAJAX.data = {
action: 'getConf',
- id: _params.id
+ id: _params.id,
+ full: _params.full || 0,
};
domUtils.ajax(paramsAJAX);
}
diff --git a/core/php/getResource.php b/core/php/getResource.php
index 9faef3ff57..f70ba961ef 100644
--- a/core/php/getResource.php
+++ b/core/php/getResource.php
@@ -42,7 +42,7 @@
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastModified) . ' GMT');
header('Etag: ' . $etagFile);
header('Cache-Control: public');
- if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified || $etagHeader == $etagFile) {
+ if (($ifModifiedSince !== false && $ifModifiedSince == $lastModified) || $etagHeader == $etagFile) {
header('HTTP/1.1 304 Not Modified');
exit;
}
diff --git a/core/php/utils.inc.php b/core/php/utils.inc.php
index c113fcf7d0..ad4c666c83 100644
--- a/core/php/utils.inc.php
+++ b/core/php/utils.inc.php
@@ -254,9 +254,9 @@ function mySqlIsHere() {
function displayException($e) {
$message = '' . $e->getMessage() . '';
- if (DEBUG) {
- $message .= 'Show traces';
- $message .= '
' . print_r($e->getTrace(), true) . ''; + if (DEBUG !== 0) { + $message .= "Show traces"; + $message .= '
' . print_r($e->getTraceAsString(), true) . ''; } return $message; } @@ -859,7 +859,11 @@ function getDirectorySize($path) { $path = realpath($path); if($path!==false && $path!='' && file_exists($path) && !is_link($path)){ foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)) as $object){ - $bytestotal += $object->getSize(); + try { + $bytestotal += $object->getSize(); + } catch (\Throwable $th) { + + } } } return $bytestotal; @@ -881,7 +885,6 @@ function sizeFormat($size) { * @return boolean */ function netMatch($network, $ip) { - $ip = trim($ip); if ($ip == trim($network)) { return true; @@ -1440,6 +1443,22 @@ function checkAndFixCron($_cron) { return $return; } +function cronIsDue($_cron){ + $schedule = explode(' ',$_cron); + if(count($schedule) == 6 && $schedule[5] != strtotime('Y')){ + return false; + } + $c = new Cron\CronExpression(checkAndFixCron($_cron), new Cron\FieldFactory); + try { + return $c->isDue(); + } catch (Exception $e) { + + } catch (Error $e) { + + } + return false; +} + function getTZoffsetMin() { $tz = date_default_timezone_get(); date_default_timezone_set("UTC"); @@ -1551,7 +1570,9 @@ function pageTitle($_page) { } function cleanComponanteName($_name) { - return strip_tags(str_replace(array('&', '#', ']', '[', '%', "\\", "/", "'", '"', "*"), '', $_name)); + $return = strip_tags(str_replace(array('&', '#', ']', '[', '%', "\\", "/", "'", '"', "*"), '', $_name)); + $return = preg_replace('/\s+/', ' ', $return); + return $return; } function startsWith($haystack, $needle) { diff --git a/core/template/scenario/scenario.default.html b/core/template/scenario/scenario.default.html index 1d75242a0b..0774702d3c 100644 --- a/core/template/scenario/scenario.default.html +++ b/core/template/scenario/scenario.default.html @@ -2,6 +2,7 @@