File manager - Edit - /home/jardides/www/Jardi-design/images/administrator/App.tar
Back
InfoParser.php 0000604 00000015735 15247131523 0007337 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch> * * @author Andreas Fischer <bantu@owncloud.com> * @author Christoph Wurst <christoph@owncloud.com> * @author Lukas Reschke <lukas@statuscode.ch> * @author Morris Jobke <hey@morrisjobke.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App; use OCP\ICache; class InfoParser { /** @var \OCP\ICache|null */ private $cache; /** * @param ICache|null $cache */ public function __construct(ICache $cache = null) { $this->cache = $cache; } /** * @param string $file the xml file to be loaded * @return null|array where null is an indicator for an error */ public function parse($file) { if (!file_exists($file)) { return null; } if(!is_null($this->cache)) { $fileCacheKey = $file . filemtime($file); if ($cachedValue = $this->cache->get($fileCacheKey)) { return json_decode($cachedValue, true); } } libxml_use_internal_errors(true); $loadEntities = libxml_disable_entity_loader(false); $xml = simplexml_load_file($file); libxml_disable_entity_loader($loadEntities); if ($xml === false) { libxml_clear_errors(); return null; } $array = $this->xmlToArray($xml); if (is_null($array)) { return null; } if (!array_key_exists('info', $array)) { $array['info'] = []; } if (!array_key_exists('remote', $array)) { $array['remote'] = []; } if (!array_key_exists('public', $array)) { $array['public'] = []; } if (!array_key_exists('types', $array)) { $array['types'] = []; } if (!array_key_exists('repair-steps', $array)) { $array['repair-steps'] = []; } if (!array_key_exists('install', $array['repair-steps'])) { $array['repair-steps']['install'] = []; } if (!array_key_exists('pre-migration', $array['repair-steps'])) { $array['repair-steps']['pre-migration'] = []; } if (!array_key_exists('post-migration', $array['repair-steps'])) { $array['repair-steps']['post-migration'] = []; } if (!array_key_exists('live-migration', $array['repair-steps'])) { $array['repair-steps']['live-migration'] = []; } if (!array_key_exists('uninstall', $array['repair-steps'])) { $array['repair-steps']['uninstall'] = []; } if (!array_key_exists('background-jobs', $array)) { $array['background-jobs'] = []; } if (!array_key_exists('two-factor-providers', $array)) { $array['two-factor-providers'] = []; } if (!array_key_exists('commands', $array)) { $array['commands'] = []; } if (!array_key_exists('activity', $array)) { $array['activity'] = []; } if (!array_key_exists('filters', $array['activity'])) { $array['activity']['filters'] = []; } if (!array_key_exists('settings', $array['activity'])) { $array['activity']['settings'] = []; } if (!array_key_exists('providers', $array['activity'])) { $array['activity']['providers'] = []; } if (array_key_exists('types', $array)) { if (is_array($array['types'])) { foreach ($array['types'] as $type => $v) { unset($array['types'][$type]); if (is_string($type)) { $array['types'][] = $type; } } } else { $array['types'] = []; } } if (isset($array['repair-steps']['install']['step']) && is_array($array['repair-steps']['install']['step'])) { $array['repair-steps']['install'] = $array['repair-steps']['install']['step']; } if (isset($array['repair-steps']['pre-migration']['step']) && is_array($array['repair-steps']['pre-migration']['step'])) { $array['repair-steps']['pre-migration'] = $array['repair-steps']['pre-migration']['step']; } if (isset($array['repair-steps']['post-migration']['step']) && is_array($array['repair-steps']['post-migration']['step'])) { $array['repair-steps']['post-migration'] = $array['repair-steps']['post-migration']['step']; } if (isset($array['repair-steps']['live-migration']['step']) && is_array($array['repair-steps']['live-migration']['step'])) { $array['repair-steps']['live-migration'] = $array['repair-steps']['live-migration']['step']; } if (isset($array['repair-steps']['uninstall']['step']) && is_array($array['repair-steps']['uninstall']['step'])) { $array['repair-steps']['uninstall'] = $array['repair-steps']['uninstall']['step']; } if (isset($array['background-jobs']['job']) && is_array($array['background-jobs']['job'])) { $array['background-jobs'] = $array['background-jobs']['job']; } if (isset($array['commands']['command']) && is_array($array['commands']['command'])) { $array['commands'] = $array['commands']['command']; } if (isset($array['activity']['filters']['filter']) && is_array($array['activity']['filters']['filter'])) { $array['activity']['filters'] = $array['activity']['filters']['filter']; } if (isset($array['activity']['settings']['setting']) && is_array($array['activity']['settings']['setting'])) { $array['activity']['settings'] = $array['activity']['settings']['setting']; } if (isset($array['activity']['providers']['provider']) && is_array($array['activity']['providers']['provider'])) { $array['activity']['providers'] = $array['activity']['providers']['provider']; } if(!is_null($this->cache)) { $this->cache->set($fileCacheKey, json_encode($array)); } return $array; } /** * @param \SimpleXMLElement $xml * @return array */ function xmlToArray($xml) { if (!$xml->children()) { return (string)$xml; } $array = []; foreach ($xml->children() as $element => $node) { $totalElement = count($xml->{$element}); if (!isset($array[$element])) { $array[$element] = $totalElement > 1 ? [] : ""; } /** @var \SimpleXMLElement $node */ // Has attributes if ($attributes = $node->attributes()) { $data = [ '@attributes' => [], ]; if (!count($node->children())){ $value = (string)$node; if (!empty($value)) { $data['@value'] = (string)$node; } } else { $data = array_merge($data, $this->xmlToArray($node)); } foreach ($attributes as $attr => $value) { $data['@attributes'][$attr] = (string)$value; } if ($totalElement > 1) { $array[$element][] = $data; } else { $array[$element] = $data; } // Just a value } else { if ($totalElement > 1) { $array[$element][] = $this->xmlToArray($node); } else { $array[$element] = $this->xmlToArray($node); } } } return $array; } } CodeChecker/PrivateCheck.php 0000604 00000003640 15247131523 0011766 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App\CodeChecker; class PrivateCheck extends AbstractCheck implements ICheck { /** * @return string */ protected function getLocalDescription() { return 'private'; } /** * @return array */ public function getLocalClasses() { return [ // classes replaced by the public api 'OC_API' => '6.0.0', 'OC_App' => '6.0.0', 'OC_AppConfig' => '6.0.0', 'OC_Avatar' => '6.0.0', 'OC_BackgroundJob' => '6.0.0', 'OC_Config' => '6.0.0', 'OC_DB' => '6.0.0', 'OC_Files' => '6.0.0', 'OC_Helper' => '6.0.0', 'OC_Hook' => '6.0.0', 'OC_Image' => '6.0.0', 'OC_JSON' => '6.0.0', 'OC_L10N' => '6.0.0', 'OC_Log' => '6.0.0', 'OC_Mail' => '6.0.0', 'OC_Preferences' => '6.0.0', 'OC_Search_Provider' => '6.0.0', 'OC_Search_Result' => '6.0.0', 'OC_Request' => '6.0.0', 'OC_Response' => '6.0.0', 'OC_Template' => '6.0.0', 'OC_User' => '6.0.0', 'OC_Util' => '6.0.0', ]; } /** * @return array */ public function getLocalConstants() { return []; } /** * @return array */ public function getLocalFunctions() { return []; } /** * @return array */ public function getLocalMethods() { return []; } } CodeChecker/DatabaseSchemaChecker.php 0000604 00000007547 15247131523 0013542 0 ustar 00 <?php /** * @copyright Copyright (c) 2017, Joas Schilling <coding@schilljs.com> * * @author Joas Schilling <coding@schilljs.com> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\CodeChecker; class DatabaseSchemaChecker { /** * @param string $appId * @return array */ public function analyse($appId) { $appPath = \OC_App::getAppPath($appId); if ($appPath === false) { throw new \RuntimeException("No app with given id <$appId> known."); } if (!file_exists($appPath . '/appinfo/database.xml')) { return ['errors' => [], 'warnings' => []]; } libxml_use_internal_errors(true); $loadEntities = libxml_disable_entity_loader(false); $xml = simplexml_load_file($appPath . '/appinfo/database.xml'); libxml_disable_entity_loader($loadEntities); $errors = $warnings = []; foreach ($xml->table as $table) { // Table names if (strpos($table->name, '*dbprefix*') !== 0) { $errors[] = 'Database schema error: name of table ' . $table->name . ' does not start with *dbprefix*'; } $tableName = substr($table->name, strlen('*dbprefix*')); if (strpos($tableName, '*dbprefix*') !== false) { $warnings[] = 'Database schema warning: *dbprefix* should only appear once in name of table ' . $table->name; } if (strlen($tableName) > 27) { $errors[] = 'Database schema error: Name of table ' . $table->name . ' is too long (' . strlen($tableName) . '), max. 27 characters (21 characters for tables with autoincrement) + *dbprefix* allowed'; } $hasAutoIncrement = false; // Column names foreach ($table->declaration->field as $column) { if (strpos($column->name, '*dbprefix*') !== false) { $warnings[] = 'Database schema warning: *dbprefix* should not appear in name of column ' . $column->name . ' on table ' . $table->name; } if (strlen($column->name) > 30) { $errors[] = 'Database schema error: Name of column ' . $column->name . ' on table ' . $table->name . ' is too long (' . strlen($tableName) . '), max. 30 characters allowed'; } if ($column->autoincrement) { if ($hasAutoIncrement) { $errors[] = 'Database schema error: Table ' . $table->name . ' has multiple autoincrement columns'; } if (strlen($tableName) > 21) { $errors[] = 'Database schema error: Name of table ' . $table->name . ' is too long (' . strlen($tableName) . '), max. 27 characters (21 characters for tables with autoincrement) + *dbprefix* allowed'; } $hasAutoIncrement = true; } } // Index names foreach ($table->declaration->index as $index) { $hasPrefix = strpos($index->name, '*dbprefix*'); if ($hasPrefix !== false && $hasPrefix !== 0) { $warnings[] = 'Database schema warning: *dbprefix* should only appear at the beginning in name of index ' . $index->name . ' on table ' . $table->name; } $indexName = $hasPrefix === 0 ? substr($index->name, strlen('*dbprefix*')) : $index->name; if (strlen($indexName) > 27) { $errors[] = 'Database schema error: Name of index ' . $index->name . ' on table ' . $table->name . ' is too long (' . strlen($tableName) . '), max. 27 characters + *dbprefix* allowed'; } } } return ['errors' => $errors, 'warnings' => $warnings]; } } CodeChecker/AbstractCheck.php 0000604 00000007120 15247131523 0012114 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App\CodeChecker; abstract class AbstractCheck implements ICheck { /** @var ICheck */ protected $check; /** * @param ICheck $check */ public function __construct(ICheck $check) { $this->check = $check; } /** * @param int $errorCode * @param string $errorObject * @return string */ public function getDescription($errorCode, $errorObject) { switch ($errorCode) { case CodeChecker::STATIC_CALL_NOT_ALLOWED: $functions = $this->getLocalFunctions(); $functions = array_change_key_case($functions, CASE_LOWER); if (isset($functions[$errorObject])) { return $this->getLocalDescription(); } // no break; case CodeChecker::CLASS_EXTENDS_NOT_ALLOWED: case CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED: case CodeChecker::CLASS_NEW_NOT_ALLOWED: case CodeChecker::CLASS_USE_NOT_ALLOWED: $classes = $this->getLocalClasses(); $classes = array_change_key_case($classes, CASE_LOWER); if (isset($classes[$errorObject])) { return $this->getLocalDescription(); } break; case CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED: $constants = $this->getLocalConstants(); $constants = array_change_key_case($constants, CASE_LOWER); if (isset($constants[$errorObject])) { return $this->getLocalDescription(); } break; case CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED: $methods = $this->getLocalMethods(); $methods = array_change_key_case($methods, CASE_LOWER); if (isset($methods[$errorObject])) { return $this->getLocalDescription(); } break; } return $this->check->getDescription($errorCode, $errorObject); } /** * @return string */ abstract protected function getLocalDescription(); /** * @return array */ abstract protected function getLocalClasses(); /** * @return array */ abstract protected function getLocalConstants(); /** * @return array */ abstract protected function getLocalFunctions(); /** * @return array */ abstract protected function getLocalMethods(); /** * @return array E.g.: `'ClassName' => 'oc version',` */ public function getClasses() { return array_merge($this->getLocalClasses(), $this->check->getClasses()); } /** * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` */ public function getConstants() { return array_merge($this->getLocalConstants(), $this->check->getConstants()); } /** * @return array E.g.: `'functionName' => 'oc version',` */ public function getFunctions() { return array_merge($this->getLocalFunctions(), $this->check->getFunctions()); } /** * @return array E.g.: `'ClassName::methodName' => 'oc version',` */ public function getMethods() { return array_merge($this->getLocalMethods(), $this->check->getMethods()); } /** * @return bool */ public function checkStrongComparisons() { return $this->check->checkStrongComparisons(); } } CodeChecker/InfoChecker.php 0000604 00000010673 15247131523 0011602 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App\CodeChecker; use OC\App\InfoParser; use OC\Hooks\BasicEmitter; class InfoChecker extends BasicEmitter { /** @var InfoParser */ private $infoParser; private $mandatoryFields = [ 'author', 'description', 'id', 'licence', 'name', ]; private $optionalFields = [ 'bugs', 'category', 'default_enable', 'dependencies', // TODO: Mandatory as of ownCloud 11 'documentation', 'namespace', 'ocsid', 'public', 'remote', 'repository', 'types', 'version', 'website', ]; private $deprecatedFields = [ 'info', 'require', 'requiremax', 'requiremin', 'shipped', 'standalone', ]; public function __construct(InfoParser $infoParser) { $this->infoParser = $infoParser; } /** * @param string $appId * @return array */ public function analyse($appId) { $appPath = \OC_App::getAppPath($appId); if ($appPath === false) { throw new \RuntimeException("No app with given id <$appId> known."); } $errors = []; $info = $this->infoParser->parse($appPath . '/appinfo/info.xml'); if (isset($info['dependencies']['owncloud']['@attributes']['min-version']) && (isset($info['requiremin']) || isset($info['require']))) { $this->emit('InfoChecker', 'duplicateRequirement', ['min']); $errors[] = [ 'type' => 'duplicateRequirement', 'field' => 'min', ]; } else if ( !isset($info['dependencies']['owncloud']['@attributes']['min-version']) && !isset($info['dependencies']['nextcloud']['@attributes']['min-version']) ) { $this->emit('InfoChecker', 'missingRequirement', ['min']); } if (isset($info['dependencies']['owncloud']['@attributes']['max-version']) && isset($info['requiremax'])) { $this->emit('InfoChecker', 'duplicateRequirement', ['max']); $errors[] = [ 'type' => 'duplicateRequirement', 'field' => 'max', ]; } else if ( !isset($info['dependencies']['owncloud']['@attributes']['max-version']) && !isset($info['dependencies']['nextcloud']['@attributes']['max-version']) ) { $this->emit('InfoChecker', 'missingRequirement', ['max']); } foreach ($info as $key => $value) { if(is_array($value)) { $value = json_encode($value); } if (in_array($key, $this->mandatoryFields)) { $this->emit('InfoChecker', 'mandatoryFieldFound', [$key, $value]); continue; } if (in_array($key, $this->optionalFields)) { $this->emit('InfoChecker', 'optionalFieldFound', [$key, $value]); continue; } if (in_array($key, $this->deprecatedFields)) { // skip empty arrays - empty arrays for remote and public are always added if($value === '[]' && in_array($key, ['public', 'remote', 'info'])) { continue; } $this->emit('InfoChecker', 'deprecatedFieldFound', [$key, $value]); continue; } $this->emit('InfoChecker', 'unusedFieldFound', [$key, $value]); } foreach ($this->mandatoryFields as $key) { if(!isset($info[$key])) { $this->emit('InfoChecker', 'mandatoryFieldMissing', [$key]); $errors[] = [ 'type' => 'mandatoryFieldMissing', 'field' => $key, ]; } } $versionFile = $appPath . '/appinfo/version'; if (is_file($versionFile)) { $version = trim(file_get_contents($versionFile)); if (isset($info['version'])) { if($info['version'] !== $version) { $this->emit('InfoChecker', 'differentVersions', [$version, $info['version']]); $errors[] = [ 'type' => 'differentVersions', 'message' => 'appinfo/version: ' . $version . ' - appinfo/info.xml: ' . $info['version'], ]; } else { $this->emit('InfoChecker', 'sameVersions', [$versionFile]); } } else { $this->emit('InfoChecker', 'migrateVersion', [$version]); } } return $errors; } } CodeChecker/NodeVisitor.php 0000604 00000024670 15247131523 0011671 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App\CodeChecker; use PhpParser\Node; use PhpParser\Node\Name; use PhpParser\NodeVisitorAbstract; class NodeVisitor extends NodeVisitorAbstract { /** @var ICheck */ protected $list; /** @var string */ protected $blackListDescription; /** @var string[] */ protected $blackListedClassNames; /** @var string[] */ protected $blackListedConstants; /** @var string[] */ protected $blackListedFunctions; /** @var string[] */ protected $blackListedMethods; /** @var bool */ protected $checkEqualOperatorUsage; /** @var string[] */ protected $errorMessages; /** * @param ICheck $list */ public function __construct(ICheck $list) { $this->list = $list; $this->blackListedClassNames = []; foreach ($list->getClasses() as $class => $blackListInfo) { if (is_numeric($class) && is_string($blackListInfo)) { $class = $blackListInfo; $blackListInfo = null; } $class = strtolower($class); $this->blackListedClassNames[$class] = $class; } $this->blackListedConstants = []; foreach ($list->getConstants() as $constantName => $blackListInfo) { $constantName = strtolower($constantName); $this->blackListedConstants[$constantName] = $constantName; } $this->blackListedFunctions = []; foreach ($list->getFunctions() as $functionName => $blackListInfo) { $functionName = strtolower($functionName); $this->blackListedFunctions[$functionName] = $functionName; } $this->blackListedMethods = []; foreach ($list->getMethods() as $functionName => $blackListInfo) { $functionName = strtolower($functionName); $this->blackListedMethods[$functionName] = $functionName; } $this->checkEqualOperatorUsage = $list->checkStrongComparisons(); $this->errorMessages = [ CodeChecker::CLASS_EXTENDS_NOT_ALLOWED => "%s class must not be extended", CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED => "%s interface must not be implemented", CodeChecker::STATIC_CALL_NOT_ALLOWED => "Static method of %s class must not be called", CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED => "Constant of %s class must not not be fetched", CodeChecker::CLASS_NEW_NOT_ALLOWED => "%s class must not be instantiated", CodeChecker::CLASS_USE_NOT_ALLOWED => "%s class must not be imported with a use statement", CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED => "Method of %s class must not be called", CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED => "is discouraged", ]; } /** @var array */ public $errors = []; public function enterNode(Node $node) { if ($this->checkEqualOperatorUsage && $node instanceof Node\Expr\BinaryOp\Equal) { $this->errors[]= [ 'disallowedToken' => '==', 'errorCode' => CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED, 'line' => $node->getLine(), 'reason' => $this->buildReason('==', CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED) ]; } if ($this->checkEqualOperatorUsage && $node instanceof Node\Expr\BinaryOp\NotEqual) { $this->errors[]= [ 'disallowedToken' => '!=', 'errorCode' => CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED, 'line' => $node->getLine(), 'reason' => $this->buildReason('!=', CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED) ]; } if ($node instanceof Node\Stmt\Class_) { if (!is_null($node->extends)) { $this->checkBlackList($node->extends->toString(), CodeChecker::CLASS_EXTENDS_NOT_ALLOWED, $node); } foreach ($node->implements as $implements) { $this->checkBlackList($implements->toString(), CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED, $node); } } if ($node instanceof Node\Expr\StaticCall) { if (!is_null($node->class)) { if ($node->class instanceof Name) { $this->checkBlackList($node->class->toString(), CodeChecker::STATIC_CALL_NOT_ALLOWED, $node); $this->checkBlackListFunction($node->class->toString(), $node->name, $node); $this->checkBlackListMethod($node->class->toString(), $node->name, $node); } if ($node->class instanceof Node\Expr\Variable) { /** * TODO: find a way to detect something like this: * $c = "OC_API"; * $n = $c::call(); */ // $this->checkBlackListMethod($node->class->..., $node->name, $node); } } } if ($node instanceof Node\Expr\MethodCall) { if (!is_null($node->var)) { if ($node->var instanceof Node\Expr\Variable) { /** * TODO: find a way to detect something like this: * $c = new OC_API(); * $n = $c::call(); * $n = $c->call(); */ // $this->checkBlackListMethod($node->var->..., $node->name, $node); } } } if ($node instanceof Node\Expr\ClassConstFetch) { if (!is_null($node->class)) { if ($node->class instanceof Name) { $this->checkBlackList($node->class->toString(), CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED, $node); } if ($node->class instanceof Node\Expr\Variable) { /** * TODO: find a way to detect something like this: * $c = "OC_API"; * $n = $i::ADMIN_AUTH; */ } else { $this->checkBlackListConstant($node->class->toString(), $node->name, $node); } } } if ($node instanceof Node\Expr\New_) { if (!is_null($node->class)) { if ($node->class instanceof Name) { $this->checkBlackList($node->class->toString(), CodeChecker::CLASS_NEW_NOT_ALLOWED, $node); } if ($node->class instanceof Node\Expr\Variable) { /** * TODO: find a way to detect something like this: * $c = "OC_API"; * $n = new $i; */ } } } if ($node instanceof Node\Stmt\UseUse) { $this->checkBlackList($node->name->toString(), CodeChecker::CLASS_USE_NOT_ALLOWED, $node); if ($node->alias) { $this->addUseNameToBlackList($node->name->toString(), $node->alias); } else { $this->addUseNameToBlackList($node->name->toString(), $node->name->getLast()); } } } /** * Check whether an alias was introduced for a namespace of a blacklisted class * * Example: * - Blacklist entry: OCP\AppFramework\IApi * - Name: OCP\AppFramework * - Alias: OAF * => new blacklist entry: OAF\IApi * * @param string $name * @param string $alias */ private function addUseNameToBlackList($name, $alias) { $name = strtolower($name); $alias = strtolower($alias); foreach ($this->blackListedClassNames as $blackListedAlias => $blackListedClassName) { if (strpos($blackListedClassName, $name . '\\') === 0) { $aliasedClassName = str_replace($name, $alias, $blackListedClassName); $this->blackListedClassNames[$aliasedClassName] = $blackListedClassName; } } foreach ($this->blackListedConstants as $blackListedAlias => $blackListedConstant) { if (strpos($blackListedConstant, $name . '\\') === 0 || strpos($blackListedConstant, $name . '::') === 0) { $aliasedConstantName = str_replace($name, $alias, $blackListedConstant); $this->blackListedConstants[$aliasedConstantName] = $blackListedConstant; } } foreach ($this->blackListedFunctions as $blackListedAlias => $blackListedFunction) { if (strpos($blackListedFunction, $name . '\\') === 0 || strpos($blackListedFunction, $name . '::') === 0) { $aliasedFunctionName = str_replace($name, $alias, $blackListedFunction); $this->blackListedFunctions[$aliasedFunctionName] = $blackListedFunction; } } foreach ($this->blackListedMethods as $blackListedAlias => $blackListedMethod) { if (strpos($blackListedMethod, $name . '\\') === 0 || strpos($blackListedMethod, $name . '::') === 0) { $aliasedMethodName = str_replace($name, $alias, $blackListedMethod); $this->blackListedMethods[$aliasedMethodName] = $blackListedMethod; } } } private function checkBlackList($name, $errorCode, Node $node) { $lowerName = strtolower($name); if (isset($this->blackListedClassNames[$lowerName])) { $this->errors[]= [ 'disallowedToken' => $name, 'errorCode' => $errorCode, 'line' => $node->getLine(), 'reason' => $this->buildReason($this->blackListedClassNames[$lowerName], $errorCode) ]; } } private function checkBlackListConstant($class, $constantName, Node $node) { $name = $class . '::' . $constantName; $lowerName = strtolower($name); if (isset($this->blackListedConstants[$lowerName])) { $this->errors[]= [ 'disallowedToken' => $name, 'errorCode' => CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED, 'line' => $node->getLine(), 'reason' => $this->buildReason($this->blackListedConstants[$lowerName], CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED) ]; } } private function checkBlackListFunction($class, $functionName, Node $node) { $name = $class . '::' . $functionName; $lowerName = strtolower($name); if (isset($this->blackListedFunctions[$lowerName])) { $this->errors[]= [ 'disallowedToken' => $name, 'errorCode' => CodeChecker::STATIC_CALL_NOT_ALLOWED, 'line' => $node->getLine(), 'reason' => $this->buildReason($this->blackListedFunctions[$lowerName], CodeChecker::STATIC_CALL_NOT_ALLOWED) ]; } } private function checkBlackListMethod($class, $functionName, Node $node) { $name = $class . '::' . $functionName; $lowerName = strtolower($name); if (isset($this->blackListedMethods[$lowerName])) { $this->errors[]= [ 'disallowedToken' => $name, 'errorCode' => CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED, 'line' => $node->getLine(), 'reason' => $this->buildReason($this->blackListedMethods[$lowerName], CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED) ]; } } private function buildReason($name, $errorCode) { if (isset($this->errorMessages[$errorCode])) { $desc = $this->list->getDescription($errorCode, $name); return sprintf($this->errorMessages[$errorCode], $desc); } return "$name usage not allowed - error: $errorCode"; } } CodeChecker/DeprecationCheck.php 0000604 00000011656 15247131523 0012617 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App\CodeChecker; class DeprecationCheck extends AbstractCheck implements ICheck { /** * @return string */ protected function getLocalDescription() { return 'deprecated'; } /** * @return array E.g.: `'ClassName' => 'oc version',` */ protected function getLocalClasses() { return [ 'OC_JSON' => '8.2.0', 'OCP\Config' => '8.0.0', 'OCP\Contacts' => '8.1.0', 'OCP\DB' => '8.1.0', 'OCP\IHelper' => '8.1.0', 'OCP\JSON' => '8.1.0', 'OCP\Response' => '8.1.0', 'OCP\AppFramework\IApi' => '8.0.0', ]; } /** * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` */ protected function getLocalConstants() { return [ 'OC_API::GUEST_AUTH' => '8.2.0', 'OC_API::USER_AUTH' => '8.2.0', 'OC_API::SUBADMIN_AUTH' => '8.2.0', 'OC_API::ADMIN_AUTH' => '8.2.0', 'OC_API::RESPOND_UNAUTHORISED' => '8.2.0', 'OC_API::RESPOND_SERVER_ERROR' => '8.2.0', 'OC_API::RESPOND_NOT_FOUND' => '8.2.0', 'OC_API::RESPOND_UNKNOWN_ERROR' => '8.2.0', 'OCP::PERMISSION_CREATE' => '8.0.0', 'OCP::PERMISSION_READ' => '8.0.0', 'OCP::PERMISSION_UPDATE' => '8.0.0', 'OCP::PERMISSION_DELETE' => '8.0.0', 'OCP::PERMISSION_SHARE' => '8.0.0', 'OCP::PERMISSION_ALL' => '8.0.0', 'OCP::FILENAME_INVALID_CHARS' => '8.0.0', ]; } /** * @return array E.g.: `'functionName' => 'oc version',` */ protected function getLocalFunctions() { return [ 'OCP::image_path' => '8.0.0', 'OCP::mimetype_icon' => '8.0.0', 'OCP::preview_icon' => '8.0.0', 'OCP::publicPreview_icon' => '8.0.0', 'OCP::human_file_size' => '8.0.0', 'OCP::relative_modified_date' => '8.0.0', 'OCP::simple_file_size' => '8.0.0', 'OCP::html_select_options' => '8.0.0', ]; } /** * @return array E.g.: `'ClassName::methodName' => 'oc version',` */ protected function getLocalMethods() { return [ 'OC_L10N::get' => '8.2.0', 'OCP\Activity\IManager::publishActivity' => '8.2.0', 'OCP\App::register' => '8.1.0', 'OCP\App::addNavigationEntry' => '8.1.0', 'OCP\App::getActiveNavigationEntry' => '8.2.0', 'OCP\App::setActiveNavigationEntry' => '8.1.0', 'OCP\AppFramework\Controller::params' => '7.0.0', 'OCP\AppFramework\Controller::getParams' => '7.0.0', 'OCP\AppFramework\Controller::method' => '7.0.0', 'OCP\AppFramework\Controller::getUploadedFile' => '7.0.0', 'OCP\AppFramework\Controller::env' => '7.0.0', 'OCP\AppFramework\Controller::cookie' => '7.0.0', 'OCP\AppFramework\Controller::render' => '7.0.0', 'OCP\AppFramework\IAppContainer::getCoreApi' => '8.0.0', 'OCP\AppFramework\IAppContainer::isLoggedIn' => '8.0.0', 'OCP\AppFramework\IAppContainer::isAdminUser' => '8.0.0', 'OCP\AppFramework\IAppContainer::log' => '8.0.0', 'OCP\BackgroundJob::registerJob' => '8.1.0', 'OCP\Files::tmpFile' => '8.1.0', 'OCP\Files::tmpFolder' => '8.1.0', 'OCP\IAppConfig::getValue' => '8.0.0', 'OCP\IAppConfig::deleteKey' => '8.0.0', 'OCP\IAppConfig::getKeys' => '8.0.0', 'OCP\IAppConfig::setValue' => '8.0.0', 'OCP\IAppConfig::deleteApp' => '8.0.0', 'OCP\IDBConnection::createQueryBuilder' => '8.2.0', 'OCP\IDBConnection::getExpressionBuilder' => '8.2.0', 'OCP\ISearch::search' => '8.0.0', 'OCP\IServerContainer::getCache' => '8.2.0', 'OCP\IServerContainer::getDb' => '8.1.0', 'OCP\IServerContainer::getHTTPHelper' => '8.1.0', 'OCP\User::getUser' => '8.0.0', 'OCP\User::getUsers' => '8.1.0', 'OCP\User::getDisplayName' => '8.1.0', 'OCP\User::getDisplayNames' => '8.1.0', 'OCP\User::userExists' => '8.1.0', 'OCP\User::logout' => '8.1.0', 'OCP\User::checkPassword' => '8.1.0', 'OCP\Util::encryptedFiles' => '8.1.0', 'OCP\Util::formatDate' => '8.0.0', 'OCP\Util::generateRandomBytes' => '8.1.0', 'OCP\Util::getServerHost' => '8.1.0', 'OCP\Util::getServerProtocol' => '8.1.0', 'OCP\Util::getRequestUri' => '8.1.0', 'OCP\Util::getScriptName' => '8.1.0', 'OCP\Util::imagePath' => '8.1.0', 'OCP\Util::isValidFileName' => '8.1.0', 'OCP\Util::linkToRoute' => '8.1.0', 'OCP\Util::linkTo' => '8.1.0', 'OCP\Util::logException' => '8.2.0', 'OCP\Util::mb_str_replace' => '8.2.0', 'OCP\Util::mb_substr_replace' => '8.2.0', 'OCP\Util::sendMail' => '8.1.0', ]; } } CodeChecker/LanguageParseChecker.php 0000604 00000003205 15247131523 0013416 0 ustar 00 <?php /** * @copyright Copyright (c) 2017, Joas Schilling <coding@schilljs.com> * * @author Joas Schilling <coding@schilljs.com> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\CodeChecker; class LanguageParseChecker { /** * @param string $appId * @return array */ public function analyse($appId) { $appPath = \OC_App::getAppPath($appId); if ($appPath === false) { throw new \RuntimeException("No app with given id <$appId> known."); } if (!is_dir($appPath . '/l10n/')) { return []; } $errors = []; $directory = new \DirectoryIterator($appPath . '/l10n/'); foreach ($directory as $file) { if ($file->getExtension() !== 'json') { continue; } $content = file_get_contents($file->getPathname()); json_decode($content, true); if (json_last_error() !== JSON_ERROR_NONE) { $errors[] = 'Invalid language file found: l10n/' . $file->getFilename() . ': ' . json_last_error_msg(); } } return $errors; } } CodeChecker/CodeChecker.php 0000604 00000007072 15247131523 0011560 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App\CodeChecker; use OC\Hooks\BasicEmitter; use PhpParser\Lexer; use PhpParser\NodeTraverser; use PhpParser\Parser; use RecursiveCallbackFilterIterator; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; use RegexIterator; use SplFileInfo; class CodeChecker extends BasicEmitter { const CLASS_EXTENDS_NOT_ALLOWED = 1000; const CLASS_IMPLEMENTS_NOT_ALLOWED = 1001; const STATIC_CALL_NOT_ALLOWED = 1002; const CLASS_CONST_FETCH_NOT_ALLOWED = 1003; const CLASS_NEW_NOT_ALLOWED = 1004; const OP_OPERATOR_USAGE_DISCOURAGED = 1005; const CLASS_USE_NOT_ALLOWED = 1006; const CLASS_METHOD_CALL_NOT_ALLOWED = 1007; /** @var Parser */ private $parser; /** @var ICheck */ protected $checkList; public function __construct(ICheck $checkList) { $this->checkList = $checkList; $this->parser = new Parser(new Lexer); } /** * @param string $appId * @return array */ public function analyse($appId) { $appPath = \OC_App::getAppPath($appId); if ($appPath === false) { throw new \RuntimeException("No app with given id <$appId> known."); } return $this->analyseFolder($appId, $appPath); } /** * @param string $appId * @param string $folder * @return array */ public function analyseFolder($appId, $folder) { $errors = []; $excludedDirectories = ['vendor', '3rdparty', '.git', 'l10n', 'tests', 'test']; if ($appId === 'password_policy') { $excludedDirectories[] = 'lists'; } $excludes = array_map(function($item) use ($folder) { return $folder . '/' . $item; }, $excludedDirectories); $iterator = new RecursiveDirectoryIterator($folder, RecursiveDirectoryIterator::SKIP_DOTS); $iterator = new RecursiveCallbackFilterIterator($iterator, function($item) use ($folder, $excludes){ /** @var SplFileInfo $item */ foreach($excludes as $exclude) { if (substr($item->getPath(), 0, strlen($exclude)) === $exclude) { return false; } } return true; }); $iterator = new RecursiveIteratorIterator($iterator); $iterator = new RegexIterator($iterator, '/^.+\.php$/i'); foreach ($iterator as $file) { /** @var SplFileInfo $file */ $this->emit('CodeChecker', 'analyseFileBegin', [$file->getPathname()]); $fileErrors = $this->analyseFile($file); $this->emit('CodeChecker', 'analyseFileFinished', [$file->getPathname(), $fileErrors]); $errors = array_merge($fileErrors, $errors); } return $errors; } /** * @param string $file * @return array */ public function analyseFile($file) { $code = file_get_contents($file); $statements = $this->parser->parse($code); $visitor = new NodeVisitor($this->checkList); $traverser = new NodeTraverser; $traverser->addVisitor($visitor); $traverser->traverse($statements); return $visitor->errors; } } CodeChecker/EmptyCheck.php 0000604 00000003040 15247131523 0011444 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App\CodeChecker; class EmptyCheck implements ICheck { /** * @param int $errorCode * @param string $errorObject * @return string */ public function getDescription($errorCode, $errorObject) { return ''; } /** * @return array E.g.: `'ClassName' => 'oc version',` */ public function getClasses() { return []; } /** * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` */ public function getConstants() { return []; } /** * @return array E.g.: `'functionName' => 'oc version',` */ public function getFunctions() { return []; } /** * @return array E.g.: `'ClassName::methodName' => 'oc version',` */ public function getMethods() { return []; } /** * @return bool */ public function checkStrongComparisons() { return false; } } CodeChecker/StrongComparisonCheck.php 0000604 00000003247 15247131523 0013666 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App\CodeChecker; class StrongComparisonCheck implements ICheck { /** @var ICheck */ protected $check; /** * @param ICheck $check */ public function __construct(ICheck $check) { $this->check = $check; } /** * @param int $errorCode * @param string $errorObject * @return string */ public function getDescription($errorCode, $errorObject) { return $this->check->getDescription($errorCode, $errorObject); } /** * @return array */ public function getClasses() { return $this->check->getClasses(); } /** * @return array */ public function getConstants() { return $this->check->getConstants(); } /** * @return array */ public function getFunctions() { return $this->check->getFunctions(); } /** * @return array */ public function getMethods() { return $this->check->getMethods(); } /** * @return bool */ public function checkStrongComparisons() { return true; } } CodeChecker/ICheck.php 0000604 00000002645 15247131523 0010550 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App\CodeChecker; interface ICheck { /** * @param int $errorCode * @param string $errorObject * @return string */ public function getDescription($errorCode, $errorObject); /** * @return array E.g.: `'ClassName' => 'oc version',` */ public function getClasses(); /** * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` */ public function getConstants(); /** * @return array E.g.: `'functionName' => 'oc version',` */ public function getFunctions(); /** * @return array E.g.: `'ClassName::methodName' => 'oc version',` */ public function getMethods(); /** * @return bool */ public function checkStrongComparisons(); } AppManager.php 0000604 00000025016 15247131523 0007273 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Arthur Schiwon <blizzz@arthur-schiwon.de> * @author Bjoern Schiessle <bjoern@schiessle.org> * @author Christoph Schaefer <christophł@wolkesicher.de> * @author Christoph Wurst <christoph@owncloud.com> * @author Joas Schilling <coding@schilljs.com> * @author Lukas Reschke <lukas@statuscode.ch> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Thomas Müller <thomas.mueller@tmit.eu> * @author Vincent Petry <pvince81@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App; use OCP\App\AppPathNotFoundException; use OCP\App\IAppManager; use OCP\App\ManagerEvent; use OCP\IAppConfig; use OCP\ICacheFactory; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserSession; use Symfony\Component\EventDispatcher\EventDispatcherInterface; class AppManager implements IAppManager { /** * Apps with these types can not be enabled for certain groups only * @var string[] */ protected $protectedAppTypes = [ 'filesystem', 'prelogin', 'authentication', 'logging', 'prevent_group_restriction', ]; /** @var IUserSession */ private $userSession; /** @var IAppConfig */ private $appConfig; /** @var IGroupManager */ private $groupManager; /** @var ICacheFactory */ private $memCacheFactory; /** @var EventDispatcherInterface */ private $dispatcher; /** @var string[] $appId => $enabled */ private $installedAppsCache; /** @var string[] */ private $shippedApps; /** @var string[] */ private $alwaysEnabled; /** * @param IUserSession $userSession * @param IAppConfig $appConfig * @param IGroupManager $groupManager * @param ICacheFactory $memCacheFactory * @param EventDispatcherInterface $dispatcher */ public function __construct(IUserSession $userSession, IAppConfig $appConfig, IGroupManager $groupManager, ICacheFactory $memCacheFactory, EventDispatcherInterface $dispatcher) { $this->userSession = $userSession; $this->appConfig = $appConfig; $this->groupManager = $groupManager; $this->memCacheFactory = $memCacheFactory; $this->dispatcher = $dispatcher; } /** * @return string[] $appId => $enabled */ private function getInstalledAppsValues() { if (!$this->installedAppsCache) { $values = $this->appConfig->getValues(false, 'enabled'); $alwaysEnabledApps = $this->getAlwaysEnabledApps(); foreach($alwaysEnabledApps as $appId) { $values[$appId] = 'yes'; } $this->installedAppsCache = array_filter($values, function ($value) { return $value !== 'no'; }); ksort($this->installedAppsCache); } return $this->installedAppsCache; } /** * List all installed apps * * @return string[] */ public function getInstalledApps() { return array_keys($this->getInstalledAppsValues()); } /** * List all apps enabled for a user * * @param \OCP\IUser $user * @return string[] */ public function getEnabledAppsForUser(IUser $user) { $apps = $this->getInstalledAppsValues(); $appsForUser = array_filter($apps, function ($enabled) use ($user) { return $this->checkAppForUser($enabled, $user); }); return array_keys($appsForUser); } /** * Check if an app is enabled for user * * @param string $appId * @param \OCP\IUser $user (optional) if not defined, the currently logged in user will be used * @return bool */ public function isEnabledForUser($appId, $user = null) { if ($this->isAlwaysEnabled($appId)) { return true; } if ($user === null) { $user = $this->userSession->getUser(); } $installedApps = $this->getInstalledAppsValues(); if (isset($installedApps[$appId])) { return $this->checkAppForUser($installedApps[$appId], $user); } else { return false; } } /** * @param string $enabled * @param IUser $user * @return bool */ private function checkAppForUser($enabled, $user) { if ($enabled === 'yes') { return true; } elseif ($user === null) { return false; } else { if(empty($enabled)){ return false; } $groupIds = json_decode($enabled); if (!is_array($groupIds)) { $jsonError = json_last_error(); \OC::$server->getLogger()->warning('AppManger::checkAppForUser - can\'t decode group IDs: ' . print_r($enabled, true) . ' - json error code: ' . $jsonError, ['app' => 'lib']); return false; } $userGroups = $this->groupManager->getUserGroupIds($user); foreach ($userGroups as $groupId) { if (in_array($groupId, $groupIds, true)) { return true; } } return false; } } /** * Check if an app is installed in the instance * * @param string $appId * @return bool */ public function isInstalled($appId) { $installedApps = $this->getInstalledAppsValues(); return isset($installedApps[$appId]); } /** * Enable an app for every user * * @param string $appId * @throws AppPathNotFoundException */ public function enableApp($appId) { // Check if app exists $this->getAppPath($appId); $this->installedAppsCache[$appId] = 'yes'; $this->appConfig->setValue($appId, 'enabled', 'yes'); $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE, new ManagerEvent( ManagerEvent::EVENT_APP_ENABLE, $appId )); $this->clearAppsCache(); } /** * Whether a list of types contains a protected app type * * @param string[] $types * @return bool */ public function hasProtectedAppType($types) { if (empty($types)) { return false; } $protectedTypes = array_intersect($this->protectedAppTypes, $types); return !empty($protectedTypes); } /** * Enable an app only for specific groups * * @param string $appId * @param \OCP\IGroup[] $groups * @throws \Exception if app can't be enabled for groups */ public function enableAppForGroups($appId, $groups) { $info = $this->getAppInfo($appId); if (!empty($info['types'])) { $protectedTypes = array_intersect($this->protectedAppTypes, $info['types']); if (!empty($protectedTypes)) { throw new \Exception("$appId can't be enabled for groups."); } } $groupIds = array_map(function ($group) { /** @var \OCP\IGroup $group */ return $group->getGID(); }, $groups); $this->installedAppsCache[$appId] = json_encode($groupIds); $this->appConfig->setValue($appId, 'enabled', json_encode($groupIds)); $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, new ManagerEvent( ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, $appId, $groups )); $this->clearAppsCache(); } /** * Disable an app for every user * * @param string $appId * @throws \Exception if app can't be disabled */ public function disableApp($appId) { if ($this->isAlwaysEnabled($appId)) { throw new \Exception("$appId can't be disabled."); } unset($this->installedAppsCache[$appId]); $this->appConfig->setValue($appId, 'enabled', 'no'); $this->dispatcher->dispatch(ManagerEvent::EVENT_APP_DISABLE, new ManagerEvent( ManagerEvent::EVENT_APP_DISABLE, $appId )); $this->clearAppsCache(); } /** * Get the directory for the given app. * * @param string $appId * @return string * @throws AppPathNotFoundException if app folder can't be found */ public function getAppPath($appId) { $appPath = \OC_App::getAppPath($appId); if($appPath === false) { throw new AppPathNotFoundException('Could not find path for ' . $appId); } return $appPath; } /** * Clear the cached list of apps when enabling/disabling an app */ public function clearAppsCache() { $settingsMemCache = $this->memCacheFactory->create('settings'); $settingsMemCache->clear('listApps'); } /** * Returns a list of apps that need upgrade * * @param string $version Nextcloud version as array of version components * @return array list of app info from apps that need an upgrade * * @internal */ public function getAppsNeedingUpgrade($version) { $appsToUpgrade = []; $apps = $this->getInstalledApps(); foreach ($apps as $appId) { $appInfo = $this->getAppInfo($appId); $appDbVersion = $this->appConfig->getValue($appId, 'installed_version'); if ($appDbVersion && isset($appInfo['version']) && version_compare($appInfo['version'], $appDbVersion, '>') && \OC_App::isAppCompatible($version, $appInfo) ) { $appsToUpgrade[] = $appInfo; } } return $appsToUpgrade; } /** * Returns the app information from "appinfo/info.xml". * * @param string $appId app id * * @return array app info * * @internal */ public function getAppInfo($appId) { $appInfo = \OC_App::getAppInfo($appId); if (!isset($appInfo['version'])) { // read version from separate file $appInfo['version'] = \OC_App::getAppVersion($appId); } return $appInfo; } /** * Returns a list of apps incompatible with the given version * * @param string $version Nextcloud version as array of version components * * @return array list of app info from incompatible apps * * @internal */ public function getIncompatibleApps($version) { $apps = $this->getInstalledApps(); $incompatibleApps = array(); foreach ($apps as $appId) { $info = $this->getAppInfo($appId); if (!\OC_App::isAppCompatible($version, $info)) { $incompatibleApps[] = $info; } } return $incompatibleApps; } /** * @inheritdoc */ public function isShipped($appId) { $this->loadShippedJson(); return in_array($appId, $this->shippedApps, true); } private function isAlwaysEnabled($appId) { $alwaysEnabled = $this->getAlwaysEnabledApps(); return in_array($appId, $alwaysEnabled, true); } private function loadShippedJson() { if ($this->shippedApps === null) { $shippedJson = \OC::$SERVERROOT . '/core/shipped.json'; if (!file_exists($shippedJson)) { throw new \Exception("File not found: $shippedJson"); } $content = json_decode(file_get_contents($shippedJson), true); $this->shippedApps = $content['shippedApps']; $this->alwaysEnabled = $content['alwaysEnabled']; } } /** * @inheritdoc */ public function getAlwaysEnabledApps() { $this->loadShippedJson(); return $this->alwaysEnabled; } } PlatformRepository.php 0000604 00000015136 15247131523 0011146 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App; /** * Class PlatformRepository * * Inspired by the composer project - licensed under MIT * https://github.com/composer/composer/blob/master/src/Composer/Repository/PlatformRepository.php#L82 * * @package OC\App */ class PlatformRepository { public function __construct() { $this->packages = $this->initialize(); } protected function initialize() { $loadedExtensions = get_loaded_extensions(); $packages = array(); // Extensions scanning foreach ($loadedExtensions as $name) { if (in_array($name, array('standard', 'Core'))) { continue; } $ext = new \ReflectionExtension($name); try { $prettyVersion = $ext->getVersion(); $prettyVersion = $this->normalizeVersion($prettyVersion); } catch (\UnexpectedValueException $e) { $prettyVersion = '0'; $prettyVersion = $this->normalizeVersion($prettyVersion); } $packages[$this->buildPackageName($name)] = $prettyVersion; } foreach ($loadedExtensions as $name) { $prettyVersion = null; switch ($name) { case 'curl': $curlVersion = curl_version(); $prettyVersion = $curlVersion['version']; break; case 'iconv': $prettyVersion = ICONV_VERSION; break; case 'intl': $name = 'ICU'; if (defined('INTL_ICU_VERSION')) { $prettyVersion = INTL_ICU_VERSION; } else { $reflector = new \ReflectionExtension('intl'); ob_start(); $reflector->info(); $output = ob_get_clean(); preg_match('/^ICU version => (.*)$/m', $output, $matches); $prettyVersion = $matches[1]; } break; case 'libxml': $prettyVersion = LIBXML_DOTTED_VERSION; break; case 'openssl': $prettyVersion = preg_replace_callback('{^(?:OpenSSL\s*)?([0-9.]+)([a-z]?).*}', function ($match) { return $match[1] . (empty($match[2]) ? '' : '.' . (ord($match[2]) - 96)); }, OPENSSL_VERSION_TEXT); break; case 'pcre': $prettyVersion = preg_replace('{^(\S+).*}', '$1', PCRE_VERSION); break; case 'uuid': $prettyVersion = phpversion('uuid'); break; case 'xsl': $prettyVersion = LIBXSLT_DOTTED_VERSION; break; default: // None handled extensions have no special cases, skip continue 2; } try { $prettyVersion = $this->normalizeVersion($prettyVersion); } catch (\UnexpectedValueException $e) { continue; } $packages[$this->buildPackageName($name)] = $prettyVersion; } return $packages; } private function buildPackageName($name) { return str_replace(' ', '-', $name); } /** * @param $name * @return string */ public function findLibrary($name) { $extName = $this->buildPackageName($name); if (isset($this->packages[$extName])) { return $this->packages[$extName]; } return null; } private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)(?:[.-]?(\d+))?)?([.-]?dev)?'; /** * Normalizes a version string to be able to perform comparisons on it * * https://github.com/composer/composer/blob/master/src/Composer/Package/Version/VersionParser.php#L94 * * @param string $version * @param string $fullVersion optional complete version string to give more context * @throws \UnexpectedValueException * @return string */ public function normalizeVersion($version, $fullVersion = null) { $version = trim($version); if (null === $fullVersion) { $fullVersion = $version; } // ignore aliases and just assume the alias is required instead of the source if (preg_match('{^([^,\s]+) +as +([^,\s]+)$}', $version, $match)) { $version = $match[1]; } // match master-like branches if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) { return '9999999-dev'; } if ('dev-' === strtolower(substr($version, 0, 4))) { return 'dev-' . substr($version, 4); } // match classical versioning if (preg_match('{^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?' . self::$modifierRegex . '$}i', $version, $matches)) { $version = $matches[1] . (!empty($matches[2]) ? $matches[2] : '.0') . (!empty($matches[3]) ? $matches[3] : '.0') . (!empty($matches[4]) ? $matches[4] : '.0'); $index = 5; } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) { // match date-based versioning $version = preg_replace('{\D}', '-', $matches[1]); $index = 2; } elseif (preg_match('{^v?(\d{4,})(\.\d+)?(\.\d+)?(\.\d+)?' . self::$modifierRegex . '$}i', $version, $matches)) { $version = $matches[1] . (!empty($matches[2]) ? $matches[2] : '.0') . (!empty($matches[3]) ? $matches[3] : '.0') . (!empty($matches[4]) ? $matches[4] : '.0'); $index = 5; } // add version modifiers if a version was matched if (isset($index)) { if (!empty($matches[$index])) { if ('stable' === $matches[$index]) { return $version; } $version .= '-' . $this->expandStability($matches[$index]) . (!empty($matches[$index + 1]) ? $matches[$index + 1] : ''); } if (!empty($matches[$index + 2])) { $version .= '-dev'; } return $version; } $extraMessage = ''; if (preg_match('{ +as +' . preg_quote($version) . '$}', $fullVersion)) { $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version'; } elseif (preg_match('{^' . preg_quote($version) . ' +as +}', $fullVersion)) { $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-'; } throw new \UnexpectedValueException('Invalid version string "' . $version . '"' . $extraMessage); } /** * @param string $stability */ private function expandStability($stability) { $stability = strtolower($stability); switch ($stability) { case 'a': return 'alpha'; case 'b': return 'beta'; case 'p': case 'pl': return 'patch'; case 'rc': return 'RC'; default: return $stability; } } } AppStore/Version/VersionParser.php 0000604 00000004766 15247131523 0013255 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Version; /** * Class VersionParser parses the versions as sent by the Nextcloud app store * * @package OC\App\AppStore */ class VersionParser { /** * @param string $versionString * @return bool */ private function isValidVersionString($versionString) { return (bool)preg_match('/^[0-9.]+$/', $versionString); } /** * Returns the version for a version string * * @param string $versionSpec * @return Version * @throws \Exception If the version cannot be parsed */ public function getVersion($versionSpec) { // * indicates that the version is compatible with all versions if($versionSpec === '*') { return new Version('', ''); } // Count the amount of =, if it is one then it's either maximum or minimum // version. If it is two then it is maximum and minimum. $versionElements = explode(' ', $versionSpec); $firstVersion = isset($versionElements[0]) ? $versionElements[0] : ''; $firstVersionNumber = substr($firstVersion, 2); $secondVersion = isset($versionElements[1]) ? $versionElements[1] : ''; $secondVersionNumber = substr($secondVersion, 2); switch(count($versionElements)) { case 1: if(!$this->isValidVersionString($firstVersionNumber)) { break; } if(substr($firstVersion, 0, 1) === '>') { return new Version($firstVersionNumber, ''); } else { return new Version('', $firstVersionNumber); } case 2: if(!$this->isValidVersionString($firstVersionNumber) || !$this->isValidVersionString($secondVersionNumber)) { break; } return new Version($firstVersionNumber, $secondVersionNumber); } throw new \Exception( sprintf( 'Version cannot be parsed: %s', $versionSpec ) ); } } AppStore/Version/Version.php 0000604 00000002507 15247131523 0012067 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Version; class Version { /** @var string */ private $minVersion; /** @var string */ private $maxVersion; /** * @param string $minVersion * @param string $maxVersion */ public function __construct($minVersion, $maxVersion) { $this->minVersion = $minVersion; $this->maxVersion = $maxVersion; } /** * @return string */ public function getMinimumVersion() { return $this->minVersion; } /** * @return string */ public function getMaximumVersion() { return $this->maxVersion; } } AppStore/Bundles/BundleFetcher.php 0000604 00000003757 15247131523 0013133 0 ustar 00 <?php /** * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Bundles; use OCP\IL10N; class BundleFetcher { /** @var IL10N */ private $l10n; /** * @param IL10N $l10n */ public function __construct(IL10N $l10n) { $this->l10n = $l10n; } /** * @return Bundle[] */ public function getBundles() { return [ new EnterpriseBundle($this->l10n), new GroupwareBundle($this->l10n), new SocialSharingBundle($this->l10n), new EducationBundle($this->l10n), ]; } /** * Bundles that should be installed by default after installation * * @return Bundle[] */ public function getDefaultInstallationBundle() { return [ new CoreBundle($this->l10n), ]; } /** * Get the bundle with the specified identifier * * @param string $identifier * @return Bundle * @throws \BadMethodCallException If the bundle does not exist */ public function getBundleByIdentifier($identifier) { /** @var Bundle[] $bundles */ $bundles = array_merge( $this->getBundles(), $this->getDefaultInstallationBundle() ); foreach($bundles as $bundle) { if($bundle->getIdentifier() === $identifier) { return $bundle; } } throw new \BadMethodCallException('Bundle with specified identifier does not exist'); } } AppStore/Bundles/CoreBundle.php 0000604 00000002072 15247131523 0012430 0 ustar 00 <?php /** * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Bundles; class CoreBundle extends Bundle { /** * {@inheritDoc} */ public function getName() { return 'Core bundle'; } /** * {@inheritDoc} */ public function getAppIdentifiers() { return [ 'bruteforcesettings', ]; } } AppStore/Bundles/GroupwareBundle.php 0000604 00000002156 15247131523 0013516 0 ustar 00 <?php /** * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Bundles; class GroupwareBundle extends Bundle { /** * {@inheritDoc} */ public function getName() { return (string)$this->l10n->t('Groupware bundle'); } /** * {@inheritDoc} */ public function getAppIdentifiers() { return [ 'calendar', 'contacts', 'spreed', ]; } } AppStore/Bundles/Bundle.php 0000604 00000002627 15247131523 0011625 0 ustar 00 <?php /** * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Bundles; use OCP\IL10N; abstract class Bundle { /** @var IL10N */ protected $l10n; /** * @param IL10N $l10n */ public function __construct(IL10N $l10n) { $this->l10n = $l10n; } /** * Get the identifier of the bundle * * @return string */ public final function getIdentifier() { return substr(strrchr(get_class($this), '\\'), 1); } /** * Get the name of the bundle * * @return string */ public abstract function getName(); /** * Get the list of app identifiers in the bundle * * @return array */ public abstract function getAppIdentifiers(); } AppStore/Bundles/EducationBundle.php 0000604 00000002345 15247131523 0013456 0 ustar 00 <?php /** * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Bundles; class EducationBundle extends Bundle { /** * {@inheritDoc} */ public function getName() { return (string)$this->l10n->t('Education Edition'); } /** * {@inheritDoc} */ public function getAppIdentifiers() { return [ 'zenodo', 'dashboard', 'circles', 'groupfolders', 'announcementcenter', 'admin_notifications', 'quota_warning', 'orcid', 'user_saml', ]; } } AppStore/Bundles/SocialSharingBundle.php 0000604 00000002333 15247131523 0014266 0 ustar 00 <?php /** * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Bundles; class SocialSharingBundle extends Bundle { /** * {@inheritDoc} */ public function getName() { return (string)$this->l10n->t('Social sharing bundle'); } /** * {@inheritDoc} */ public function getAppIdentifiers() { return [ 'socialsharing_twitter', 'socialsharing_googleplus', 'socialsharing_facebook', 'socialsharing_email', 'socialsharing_diaspora', ]; } } AppStore/Bundles/EnterpriseBundle.php 0000604 00000002304 15247131523 0013656 0 ustar 00 <?php /** * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Bundles; class EnterpriseBundle extends Bundle { /** * {@inheritDoc} */ public function getName() { return (string)$this->l10n->t('Enterprise bundle'); } /** * {@inheritDoc} */ public function getAppIdentifiers() { return [ 'admin_audit', 'user_ldap', 'files_retention', 'files_automatedtagging', 'user_saml', 'files_accesscontrol', ]; } } AppStore/Fetcher/Fetcher.php 0000604 00000011556 15247131523 0011761 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Fetcher; use OC\Files\AppData\Factory; use GuzzleHttp\Exception\ConnectException; use OCP\AppFramework\Http; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Files\IAppData; use OCP\Files\NotFoundException; use OCP\Http\Client\IClientService; use OCP\IConfig; use OCP\ILogger; abstract class Fetcher { const INVALIDATE_AFTER_SECONDS = 300; /** @var IAppData */ protected $appData; /** @var IClientService */ protected $clientService; /** @var ITimeFactory */ protected $timeFactory; /** @var IConfig */ protected $config; /** @var Ilogger */ protected $logger; /** @var string */ protected $fileName; /** @var string */ protected $endpointUrl; /** @var string */ protected $version; /** * @param Factory $appDataFactory * @param IClientService $clientService * @param ITimeFactory $timeFactory * @param IConfig $config * @param ILogger $logger */ public function __construct(Factory $appDataFactory, IClientService $clientService, ITimeFactory $timeFactory, IConfig $config, ILogger $logger) { $this->appData = $appDataFactory->get('appstore'); $this->clientService = $clientService; $this->timeFactory = $timeFactory; $this->config = $config; $this->logger = $logger; } /** * Fetches the response from the server * * @param string $ETag * @param string $content * * @return array */ protected function fetch($ETag, $content) { $appstoreenabled = $this->config->getSystemValue('appstoreenabled', true); if (!$appstoreenabled) { return []; } $options = [ 'timeout' => 10, ]; if ($ETag !== '') { $options['headers'] = [ 'If-None-Match' => $ETag, ]; } $client = $this->clientService->newClient(); $response = $client->get($this->endpointUrl, $options); $responseJson = []; if ($response->getStatusCode() === Http::STATUS_NOT_MODIFIED) { $responseJson['data'] = json_decode($content, true); } else { $responseJson['data'] = json_decode($response->getBody(), true); $ETag = $response->getHeader('ETag'); } $responseJson['timestamp'] = $this->timeFactory->getTime(); $responseJson['ncversion'] = $this->getVersion(); if ($ETag !== '') { $responseJson['ETag'] = $ETag; } return $responseJson; } /** * Returns the array with the categories on the appstore server * * @return array */ public function get() { $appstoreenabled = $this->config->getSystemValue('appstoreenabled', true); if (!$appstoreenabled) { return []; } $rootFolder = $this->appData->getFolder('/'); $ETag = ''; $content = ''; try { // File does already exists $file = $rootFolder->getFile($this->fileName); $jsonBlob = json_decode($file->getContent(), true); if (is_array($jsonBlob)) { // No caching when the version has been updated if (isset($jsonBlob['ncversion']) && $jsonBlob['ncversion'] === $this->getVersion()) { // If the timestamp is older than 300 seconds request the files new if ((int)$jsonBlob['timestamp'] > ($this->timeFactory->getTime() - self::INVALIDATE_AFTER_SECONDS)) { return $jsonBlob['data']; } if (isset($jsonBlob['ETag'])) { $ETag = $jsonBlob['ETag']; $content = json_encode($jsonBlob['data']); } } } } catch (NotFoundException $e) { // File does not already exists $file = $rootFolder->newFile($this->fileName); } // Refresh the file content try { $responseJson = $this->fetch($ETag, $content); $file->putContent(json_encode($responseJson)); return json_decode($file->getContent(), true)['data']; } catch (ConnectException $e) { $this->logger->logException($e, ['app' => 'appstoreFetcher']); return []; } catch (\Exception $e) { return []; } } /** * Get the currently Nextcloud version * @return string */ protected function getVersion() { if ($this->version === null) { $this->version = $this->config->getSystemValue('version', '0.0.0'); } return $this->version; } /** * Set the current Nextcloud version * @param string $version */ public function setVersion($version) { $this->version = $version; } } AppStore/Fetcher/CategoryFetcher.php 0000604 00000003120 15247131523 0013443 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Fetcher; use OC\Files\AppData\Factory; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Http\Client\IClientService; use OCP\IConfig; use OCP\ILogger; class CategoryFetcher extends Fetcher { /** * @param Factory $appDataFactory * @param IClientService $clientService * @param ITimeFactory $timeFactory * @param IConfig $config * @param ILogger $logger */ public function __construct(Factory $appDataFactory, IClientService $clientService, ITimeFactory $timeFactory, IConfig $config, ILogger $logger) { parent::__construct( $appDataFactory, $clientService, $timeFactory, $config, $logger ); $this->fileName = 'categories.json'; $this->endpointUrl = 'https://apps.nextcloud.com/api/v1/categories.json'; } } AppStore/Fetcher/AppFetcher.php 0000604 00000007464 15247131523 0012425 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\App\AppStore\Fetcher; use OC\App\AppStore\Version\VersionParser; use OC\Files\AppData\Factory; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Http\Client\IClientService; use OCP\IConfig; use OCP\ILogger; class AppFetcher extends Fetcher { /** * @param Factory $appDataFactory * @param IClientService $clientService * @param ITimeFactory $timeFactory * @param IConfig $config * @param ILogger $logger */ public function __construct(Factory $appDataFactory, IClientService $clientService, ITimeFactory $timeFactory, IConfig $config, ILogger $logger) { parent::__construct( $appDataFactory, $clientService, $timeFactory, $config, $logger ); $this->fileName = 'apps.json'; $this->setEndpoint(); } /** * Only returns the latest compatible app release in the releases array * * @param string $ETag * @param string $content * * @return array */ protected function fetch($ETag, $content) { /** @var mixed[] $response */ $response = parent::fetch($ETag, $content); $ncVersion = $this->getVersion(); $ncMajorVersion = explode('.', $ncVersion)[0]; foreach($response['data'] as $dataKey => $app) { $releases = []; // Filter all compatible releases foreach($app['releases'] as $release) { // Exclude all nightly and pre-releases if($release['isNightly'] === false && strpos($release['version'], '-') === false) { // Exclude all versions not compatible with the current version $versionParser = new VersionParser(); $version = $versionParser->getVersion($release['rawPlatformVersionSpec']); if ( // Major version is bigger or equals to the minimum version of the app version_compare($ncMajorVersion, $version->getMinimumVersion(), '>=') // Major version is smaller or equals to the maximum version of the app && version_compare($ncMajorVersion, $version->getMaximumVersion(), '<=') ) { $releases[] = $release; } } } // Get the highest version $versions = []; foreach($releases as $release) { $versions[] = $release['version']; } usort($versions, 'version_compare'); $versions = array_reverse($versions); $compatible = false; if(isset($versions[0])) { $highestVersion = $versions[0]; foreach ($releases as $release) { if ((string)$release['version'] === (string)$highestVersion) { $compatible = true; $response['data'][$dataKey]['releases'] = [$release]; break; } } } if(!$compatible) { unset($response['data'][$dataKey]); } } $response['data'] = array_values($response['data']); return $response; } private function setEndpoint() { $versionArray = explode('.', $this->getVersion()); $this->endpointUrl = sprintf( 'https://apps.nextcloud.com/api/v1/platform/%d.%d.%d/apps.json', $versionArray[0], $versionArray[1], $versionArray[2] ); } /** * @param string $version */ public function setVersion($version) { parent::setVersion($version); $this->setEndpoint(); } } DependencyAnalyzer.php 0000604 00000024566 15247131523 0011055 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch> * * @author Bernhard Posselt <dev@bernhard-posselt.com> * @author Joas Schilling <coding@schilljs.com> * @author Lukas Reschke <lukas@statuscode.ch> * @author Morris Jobke <hey@morrisjobke.de> * @author Stefan Weil <sw@weilnetz.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App; use OCP\IL10N; class DependencyAnalyzer { /** @var Platform */ private $platform; /** @var \OCP\IL10N */ private $l; /** @var array */ private $appInfo; /** * @param Platform $platform * @param \OCP\IL10N $l */ function __construct(Platform $platform, IL10N $l) { $this->platform = $platform; $this->l = $l; } /** * @param array $app * @returns array of missing dependencies */ public function analyze(array $app) { $this->appInfo = $app; if (isset($app['dependencies'])) { $dependencies = $app['dependencies']; } else { $dependencies = []; } return array_merge( $this->analyzePhpVersion($dependencies), $this->analyzeDatabases($dependencies), $this->analyzeCommands($dependencies), $this->analyzeLibraries($dependencies), $this->analyzeOS($dependencies), $this->analyzeOC($dependencies, $app) ); } /** * Truncates both versions to the lowest common version, e.g. * 5.1.2.3 and 5.1 will be turned into 5.1 and 5.1, * 5.2.6.5 and 5.1 will be turned into 5.2 and 5.1 * @param string $first * @param string $second * @return string[] first element is the first version, second element is the * second version */ private function normalizeVersions($first, $second) { $first = explode('.', $first); $second = explode('.', $second); // get both arrays to the same minimum size $length = min(count($second), count($first)); $first = array_slice($first, 0, $length); $second = array_slice($second, 0, $length); return [implode('.', $first), implode('.', $second)]; } /** * Parameters will be normalized and then passed into version_compare * in the same order they are specified in the method header * @param string $first * @param string $second * @param string $operator * @return bool result similar to version_compare */ private function compare($first, $second, $operator) { // we can't normalize versions if one of the given parameters is not a // version string but null. In case one parameter is null normalization // will therefore be skipped if ($first !== null && $second !== null) { list($first, $second) = $this->normalizeVersions($first, $second); } return version_compare($first, $second, $operator); } /** * Checks if a version is bigger than another version * @param string $first * @param string $second * @return bool true if the first version is bigger than the second */ private function compareBigger($first, $second) { return $this->compare($first, $second, '>'); } /** * Checks if a version is smaller than another version * @param string $first * @param string $second * @return bool true if the first version is smaller than the second */ private function compareSmaller($first, $second) { return $this->compare($first, $second, '<'); } /** * @param array $dependencies * @return array */ private function analyzePhpVersion(array $dependencies) { $missing = []; if (isset($dependencies['php']['@attributes']['min-version'])) { $minVersion = $dependencies['php']['@attributes']['min-version']; if ($this->compareSmaller($this->platform->getPhpVersion(), $minVersion)) { $missing[] = (string)$this->l->t('PHP %s or higher is required.', $minVersion); } } if (isset($dependencies['php']['@attributes']['max-version'])) { $maxVersion = $dependencies['php']['@attributes']['max-version']; if ($this->compareBigger($this->platform->getPhpVersion(), $maxVersion)) { $missing[] = (string)$this->l->t('PHP with a version lower than %s is required.', $maxVersion); } } if (isset($dependencies['php']['@attributes']['min-int-size'])) { $intSize = $dependencies['php']['@attributes']['min-int-size']; if ($intSize > $this->platform->getIntSize()*8) { $missing[] = (string)$this->l->t('%sbit or higher PHP required.', $intSize); } } return $missing; } /** * @param array $dependencies * @return array */ private function analyzeDatabases(array $dependencies) { $missing = []; if (!isset($dependencies['database'])) { return $missing; } $supportedDatabases = $dependencies['database']; if (empty($supportedDatabases)) { return $missing; } if (!is_array($supportedDatabases)) { $supportedDatabases = array($supportedDatabases); } $supportedDatabases = array_map(function ($db) { return $this->getValue($db); }, $supportedDatabases); $currentDatabase = $this->platform->getDatabase(); if (!in_array($currentDatabase, $supportedDatabases)) { $missing[] = (string)$this->l->t('Following databases are supported: %s', join(', ', $supportedDatabases)); } return $missing; } /** * @param array $dependencies * @return array */ private function analyzeCommands(array $dependencies) { $missing = []; if (!isset($dependencies['command'])) { return $missing; } $commands = $dependencies['command']; if (!is_array($commands)) { $commands = array($commands); } if (isset($commands['@value'])) { $commands = [$commands]; } $os = $this->platform->getOS(); foreach ($commands as $command) { if (isset($command['@attributes']['os']) && $command['@attributes']['os'] !== $os) { continue; } $commandName = $this->getValue($command); if (!$this->platform->isCommandKnown($commandName)) { $missing[] = (string)$this->l->t('The command line tool %s could not be found', $commandName); } } return $missing; } /** * @param array $dependencies * @return array */ private function analyzeLibraries(array $dependencies) { $missing = []; if (!isset($dependencies['lib'])) { return $missing; } $libs = $dependencies['lib']; if (!is_array($libs)) { $libs = array($libs); } if (isset($libs['@value'])) { $libs = [$libs]; } foreach ($libs as $lib) { $libName = $this->getValue($lib); $libVersion = $this->platform->getLibraryVersion($libName); if (is_null($libVersion)) { $missing[] = (string)$this->l->t('The library %s is not available.', $libName); continue; } if (is_array($lib)) { if (isset($lib['@attributes']['min-version'])) { $minVersion = $lib['@attributes']['min-version']; if ($this->compareSmaller($libVersion, $minVersion)) { $missing[] = (string)$this->l->t('Library %s with a version higher than %s is required - available version %s.', array($libName, $minVersion, $libVersion)); } } if (isset($lib['@attributes']['max-version'])) { $maxVersion = $lib['@attributes']['max-version']; if ($this->compareBigger($libVersion, $maxVersion)) { $missing[] = (string)$this->l->t('Library %s with a version lower than %s is required - available version %s.', array($libName, $maxVersion, $libVersion)); } } } } return $missing; } /** * @param array $dependencies * @return array */ private function analyzeOS(array $dependencies) { $missing = []; if (!isset($dependencies['os'])) { return $missing; } $oss = $dependencies['os']; if (empty($oss)) { return $missing; } if (is_array($oss)) { $oss = array_map(function ($os) { return $this->getValue($os); }, $oss); } else { $oss = array($oss); } $currentOS = $this->platform->getOS(); if (!in_array($currentOS, $oss)) { $missing[] = (string)$this->l->t('Following platforms are supported: %s', join(', ', $oss)); } return $missing; } /** * @param array $dependencies * @param array $appInfo * @return array */ private function analyzeOC(array $dependencies, array $appInfo) { $missing = []; $minVersion = null; if (isset($dependencies['nextcloud']['@attributes']['min-version'])) { $minVersion = $dependencies['nextcloud']['@attributes']['min-version']; } elseif (isset($dependencies['owncloud']['@attributes']['min-version'])) { $minVersion = $dependencies['owncloud']['@attributes']['min-version']; } elseif (isset($appInfo['requiremin'])) { $minVersion = $appInfo['requiremin']; } elseif (isset($appInfo['require'])) { $minVersion = $appInfo['require']; } $maxVersion = null; if (isset($dependencies['nextcloud']['@attributes']['max-version'])) { $maxVersion = $dependencies['nextcloud']['@attributes']['max-version']; } elseif (isset($dependencies['owncloud']['@attributes']['max-version'])) { $maxVersion = $dependencies['owncloud']['@attributes']['max-version']; } elseif (isset($appInfo['requiremax'])) { $maxVersion = $appInfo['requiremax']; } if (!is_null($minVersion)) { if ($this->compareSmaller($this->platform->getOcVersion(), $minVersion)) { $missing[] = (string)$this->l->t('Server version %s or higher is required.', $this->toVisibleVersion($minVersion)); } } if (!is_null($maxVersion)) { if ($this->compareBigger($this->platform->getOcVersion(), $maxVersion)) { $missing[] = (string)$this->l->t('Server version %s or lower is required.', $this->toVisibleVersion($maxVersion)); } } return $missing; } /** * Map the internal version number to the Nextcloud version * * @param string $version * @return string */ protected function toVisibleVersion($version) { switch ($version) { case '9.1': return '10'; default: if (strpos($version, '9.1.') === 0) { $version = '10.0.' . substr($version, 4); } return $version; } } /** * @param $element * @return mixed */ private function getValue($element) { if (isset($element['@value'])) return $element['@value']; return (string)$element; } } Platform.php 0000604 00000004037 15247131523 0007044 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Bernhard Posselt <dev@bernhard-posselt.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\App; use OCP\IConfig; /** * Class Platform * * This class basically abstracts any kind of information which can be retrieved from the underlying system. * * @package OC\App */ class Platform { /** * @param IConfig $config */ function __construct(IConfig $config) { $this->config = $config; } /** * @return string */ public function getPhpVersion() { return phpversion(); } /** * @return int */ public function getIntSize() { return PHP_INT_SIZE; } /** * @return string */ public function getOcVersion() { $v = \OCP\Util::getVersion(); return join('.', $v); } /** * @return string */ public function getDatabase() { $dbType = $this->config->getSystemValue('dbtype', 'sqlite'); if ($dbType === 'sqlite3') { $dbType = 'sqlite'; } return $dbType; } /** * @return string */ public function getOS() { return php_uname('s'); } /** * @param $command * @return bool */ public function isCommandKnown($command) { $path = \OC_Helper::findBinaryPath($command); return ($path !== null); } public function getLibraryVersion($name) { $repo = new PlatformRepository(); $lib = $repo->findLibrary($name); return $lib; } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0 |
proxy
|
phpinfo
|
Settings