* don't install plugin when requirements are not satisfied

This commit is contained in:
slawkens 2020-02-15 22:41:52 +01:00
parent 2a9c28e63b
commit 518ae4d97a
5 changed files with 239 additions and 237 deletions

View File

@ -87,6 +87,7 @@
* auto detected browser language in select language * auto detected browser language in select language
### Plugins ### Plugins
* sandbox for plugins, don't install when requirements are not satisfied
* allow comments inside plugin json file (php style) * allow comments inside plugin json file (php style)
* new require options for plugins: (look into example.json) * new require options for plugins: (look into example.json)
* require database version of the MyAAC schema * require database version of the MyAAC schema

1
TODO
View File

@ -2,7 +2,6 @@
0.* 0.*
* support duplicated vocation names with different ids * support duplicated vocation names with different ids
* sandbox for plugins, don't install when requirements are not passed
* add changelog management interface * add changelog management interface
* kathrine tickets - show/hide * kathrine tickets - show/hide
* csrf token protection * csrf token protection

View File

@ -33,7 +33,7 @@ if(Plugins::install($path_to_file)) {
echo 'WARNING: ' . $warning; echo 'WARNING: ' . $warning;
} }
$info = Plugins::getPlugin(); $info = Plugins::getPluginJson();
echo (isset($info['name']) ? $info['name'] . ' p' : 'P') . 'lugin has been successfully installed.' . PHP_EOL; echo (isset($info['name']) ? $info['name'] . ' p' : 'P') . 'lugin has been successfully installed.' . PHP_EOL;
} }
else { else {

View File

@ -43,7 +43,7 @@ use Composer\Semver\Semver;
class Plugins { class Plugins {
private static $warnings = array(); private static $warnings = array();
private static $error = null; private static $error = null;
private static $plugin = array(); private static $plugin_json = array();
public static function getHooks() public static function getHooks()
{ {
@ -60,7 +60,7 @@ class Plugins {
$string = file_get_contents(PLUGINS . $filename . '.json'); $string = file_get_contents(PLUGINS . $filename . '.json');
$string = self::removeComments($string); $string = self::removeComments($string);
$plugin = json_decode($string, true); $plugin = json_decode($string, true);
self::$plugin = $plugin; self::$plugin_json = $plugin;
if ($plugin == null) { if ($plugin == null) {
self::$warnings[] = 'Cannot load ' . $filename . '.json. File might be not a valid json code.'; self::$warnings[] = 'Cannot load ' . $filename . '.json. File might be not a valid json code.';
continue; continue;
@ -98,7 +98,11 @@ class Plugins {
} }
$zip = new ZipArchive(); $zip = new ZipArchive();
if($zip->open($file)) { if($zip->open($file) !== true) {
self::$error = 'There was a problem with opening zip archive.';
return false;
}
for ($i = 0; $i < $zip->numFiles; $i++) { for ($i = 0; $i < $zip->numFiles; $i++) {
$tmp = $zip->getNameIndex($i); $tmp = $zip->getNameIndex($i);
if(pathinfo($tmp, PATHINFO_DIRNAME) == 'plugins' && pathinfo($tmp, PATHINFO_EXTENSION) == 'json') if(pathinfo($tmp, PATHINFO_DIRNAME) == 'plugins' && pathinfo($tmp, PATHINFO_EXTENSION) == 'json')
@ -110,41 +114,49 @@ class Plugins {
return false; return false;
} }
if($zip->extractTo(BASE)) { // place in the directory with same name $plugin_temp_dir = CACHE . 'plugins/' . str_replace('.zip', '', basename($file)) . '/';
$file_name = BASE . $json_file; if(!$zip->extractTo($plugin_temp_dir)) { // place in cache dir
if(!file_exists($file_name)) { self::$error = 'There was a problem with extracting zip archive to cache directory.';
self::$error = "Cannot load " . $file_name . ". File doesn't exist."; $zip->close();
return false; return false;
} }
else {
self::$error = 'There was a problem with extracting zip archive.';
$file_name = $plugin_temp_dir . $json_file;
if(!file_exists($file_name)) {
self::$error = "Cannot load " . $file_name . ". File doesn't exist.";
$zip->close();
return false;
}
$string = file_get_contents($file_name); $string = file_get_contents($file_name);
$string = self::removeComments($string); $string = self::removeComments($string);
$plugin = json_decode($string, true); $plugin_json = json_decode($string, true);
self::$plugin = $plugin; self::$plugin_json = $plugin_json;
if ($plugin == null) { if ($plugin_json == null) {
self::$warnings[] = 'Cannot load ' . $file_name . '. File might be not a valid json code.'; self::$warnings[] = 'Cannot load ' . $file_name . '. File might be not a valid json code.';
} }
else { else {
$continue = true; $continue = true;
if(!isset($plugin['name'])) { if(!isset($plugin_json['name']) || empty(trim($plugin_json['name']))) {
self::$warnings[] = 'Plugin "name" tag is not set.'; self::$warnings[] = 'Plugin "name" tag is not set.';
} }
if(!isset($plugin['description'])) { if(!isset($plugin_json['description']) || empty(trim($plugin_json['description']))) {
self::$warnings[] = 'Plugin "description" tag is not set.'; self::$warnings[] = 'Plugin "description" tag is not set.';
} }
if(!isset($plugin['version'])) { if(!isset($plugin_json['version']) || empty(trim($plugin_json['version']))) {
self::$warnings[] = 'Plugin "version" tag is not set.'; self::$warnings[] = 'Plugin "version" tag is not set.';
} }
if(!isset($plugin['author'])) { if(!isset($plugin_json['author']) || empty(trim($plugin_json['author']))) {
self::$warnings[] = 'Plugin "author" tag is not set.'; self::$warnings[] = 'Plugin "author" tag is not set.';
} }
if(!isset($plugin['contact'])) { if(!isset($plugin_json['contact']) || empty(trim($plugin_json['contact']))) {
self::$warnings[] = 'Plugin "contact" tag is not set.'; self::$warnings[] = 'Plugin "contact" tag is not set.';
} }
if(isset($plugin['require'])) { if(isset($plugin_json['require'])) {
$require = $plugin['require']; $require = $plugin_json['require'];
$myaac_satified = true; $myaac_satified = true;
if(isset($require['myaac_'])) { if(isset($require['myaac_'])) {
@ -162,54 +174,56 @@ class Plugins {
if(!$myaac_satified) { if(!$myaac_satified) {
self::$error = "Your AAC version doesn't meet the requirement of this plugin. Required version is: " . $require_myaac . ", and you're using version " . MYAAC_VERSION . "."; self::$error = "Your AAC version doesn't meet the requirement of this plugin. Required version is: " . $require_myaac . ", and you're using version " . MYAAC_VERSION . ".";
$continue = false; return false;
} }
$php_satified = true; $php_satisfied = true;
if(isset($require['php_'])) { if(isset($require['php_'])) {
$require_php = $require['php_']; $require_php = $require['php_'];
if(!Semver::satisfies(phpversion(), $require_php)) { if(!Semver::satisfies(phpversion(), $require_php)) {
$php_satified = false; $php_satisfied = false;
} }
} }
else if(isset($require['php'])) { else if(isset($require['php'])) {
$require_php = $require['php']; $require_php = $require['php'];
if(version_compare(phpversion(), $require_php, '<')) { if(version_compare(phpversion(), $require_php, '<')) {
$php_satified = false; $php_satisfied = false;
} }
} }
if(!$php_satified) { if(!$php_satisfied) {
self::$error = "Your PHP version doesn't meet the requirement of this plugin. Required version is: " . $require_php . ", and you're using version " . phpversion() . "."; self::$error = "Your PHP version doesn't meet the requirement of this plugin. Required version is: " . $require_php . ", and you're using version " . phpversion() . ".";
$continue = false; $continue = false;
} }
$database_satified = true; $database_satisfied = true;
if(isset($require['database_'])) { if(isset($require['database_'])) {
$require_database = $require['database_']; $require_database = $require['database_'];
if(!Semver::satisfies(DATABASE_VERSION, $require_database)) { if(!Semver::satisfies(DATABASE_VERSION, $require_database)) {
$database_satified = false; $database_satisfied = false;
} }
} }
else if(isset($require['database'])) { else if(isset($require['database'])) {
$require_database = $require['database']; $require_database = $require['database'];
if(version_compare(DATABASE_VERSION, $require_database, '<')) { if(version_compare(DATABASE_VERSION, $require_database, '<')) {
$database_satified = false; $database_satisfied = false;
} }
} }
if(!$database_satified) { if(!$database_satisfied) {
self::$error = "Your database version doesn't meet the requirement of this plugin. Required version is: " . $require_database . ", and you're using version " . DATABASE_VERSION . "."; self::$error = "Your database version doesn't meet the requirement of this plugin. Required version is: " . $require_database . ", and you're using version " . DATABASE_VERSION . ".";
$continue = false; $continue = false;
} }
if($continue) { if($continue) {
foreach($require as $req => $version) { foreach($require as $req => $version) {
$req = strtolower(trim($req));
$version = trim($version);
if(in_array($req, array('myaac', 'myaac_', 'php', 'php_', 'database', 'database_'))) { if(in_array($req, array('myaac', 'myaac_', 'php', 'php_', 'database', 'database_'))) {
continue; continue;
} }
$req = strtolower($req);
if(in_array($req, array('php-ext', 'php-extension'))) { // require php extension if(in_array($req, array('php-ext', 'php-extension'))) { // require php extension
if(!extension_loaded($version)) { if(!extension_loaded($version)) {
self::$error = "This plugin requires php extension: " . $version . " to be installed."; self::$error = "This plugin requires php extension: " . $version . " to be installed.";
@ -254,16 +268,22 @@ class Plugins {
} }
if($continue) { if($continue) {
if (isset($plugin['install'])) { if (isset($plugin_json['install'])) {
if (file_exists(BASE . $plugin['install'])) { if (file_exists(BASE . $plugin_json['install'])) {
$db->revalidateCache(); $db->revalidateCache();
require BASE . $plugin['install']; require BASE . $plugin_json['install'];
$db->revalidateCache(); $db->revalidateCache();
} }
else else
self::$warnings[] = 'Cannot load install script. Your plugin might be not working correctly.'; self::$warnings[] = 'Cannot load install script. Your plugin might be not working correctly.';
} }
if(!$zip->extractTo(BASE)) { // "Real" Install
self::$error = 'There was a problem with extracting zip archive to base directory.';
$zip->close();
return false;
}
$cache = Cache::getInstance(); $cache = Cache::getInstance();
if($cache->enabled()) { if($cache->enabled()) {
$cache->delete('templates'); $cache->delete('templates');
@ -271,34 +291,20 @@ class Plugins {
$cache->delete('template_menus'); $cache->delete('template_menus');
} }
$zip->close();
return true; return true;
} }
} }
}
}
else {
self::$error = 'There was a problem with extracting zip archive.';
}
$zip->close();
}
else {
self::$error = 'There was a problem with opening zip archive.';
}
return false; return false;
} }
public static function uninstall($plugin_name) { public static function uninstall($plugin_name)
global $db; {
$filename = BASE . 'plugins/' . $plugin_name . '.json'; $filename = BASE . 'plugins/' . $plugin_name . '.json';
if(!file_exists($filename)) { if(!file_exists($filename)) {
self::$error = 'Plugin ' . $plugin_name . ' does not exist.'; self::$error = 'Plugin ' . $plugin_name . ' does not exist.';
return false; return false;
} }
else {
$string = file_get_contents($filename); $string = file_get_contents($filename);
$string = self::removeComments($string); $string = self::removeComments($string);
$plugin_info = json_decode($string, true); $plugin_info = json_decode($string, true);
@ -306,12 +312,12 @@ class Plugins {
self::$error = 'Cannot load plugin info ' . $plugin_name . '.json'; self::$error = 'Cannot load plugin info ' . $plugin_name . '.json';
return false; return false;
} }
else {
if(!isset($plugin_info['uninstall'])) { if(!isset($plugin_info['uninstall'])) {
self::$error = "Plugin doesn't have uninstall options defined. Skipping..."; self::$error = "Plugin doesn't have uninstall options defined. Skipping...";
return false; return false;
} }
else {
$success = true; $success = true;
foreach($plugin_info['uninstall'] as $file) { foreach($plugin_info['uninstall'] as $file) {
if(strpos($file, '/') === 0) { if(strpos($file, '/') === 0) {
@ -332,12 +338,10 @@ class Plugins {
if($success) { if($success) {
foreach($plugin_info['uninstall'] as $file) { foreach($plugin_info['uninstall'] as $file) {
if(!deleteDirectory(BASE . $file)) { if(!deleteDirectory(BASE . $file)) {
self::$warnings[] = 'Cannot delete: ' . $$file; self::$warnings[] = 'Cannot delete: ' . $file;
}
} }
} }
if($success) {
$cache = Cache::getInstance(); $cache = Cache::getInstance();
if($cache->enabled()) { if($cache->enabled()) {
$cache->delete('templates'); $cache->delete('templates');
@ -347,9 +351,6 @@ class Plugins {
return true; return true;
} }
}
}
}
return false; return false;
} }
@ -381,8 +382,8 @@ class Plugins {
return self::$error; return self::$error;
} }
public static function getPlugin() { public static function getPluginJson() {
return self::$plugin; return self::$plugin_json;
} }
public static function removeComments($string) { public static function removeComments($string) {

View File

@ -69,7 +69,7 @@ if (isset($_REQUEST['uninstall'])) {
warning($warning); warning($warning);
} }
$info = Plugins::getPlugin(); $info = Plugins::getPluginJson();
success((isset($info['name']) ? '<strong>' . $info['name'] . '</strong> p' : 'P') . 'lugin has been successfully installed.'); success((isset($info['name']) ? '<strong>' . $info['name'] . '</strong> p' : 'P') . 'lugin has been successfully installed.');
} else { } else {
$error = Plugins::getError(); $error = Plugins::getError();
@ -93,6 +93,7 @@ foreach (get_plugins() as $plugin) {
$string = file_get_contents(BASE . 'plugins/' . $plugin . '.json'); $string = file_get_contents(BASE . 'plugins/' . $plugin . '.json');
$string = Plugins::removeComments($string); $string = Plugins::removeComments($string);
$plugin_info = json_decode($string, true); $plugin_info = json_decode($string, true);
if ($plugin_info == false) { if ($plugin_info == false) {
warning('Cannot load plugin info ' . $plugin . '.json'); warning('Cannot load plugin info ' . $plugin . '.json');
} else { } else {