diff options
author | Morris Jobke <hey@morrisjobke.de> | 2018-02-16 22:56:10 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-16 22:56:10 +0100 |
commit | 57e0881a9eb206cb9c3894af600c5ccf4b8b8ff7 (patch) | |
tree | 5324fd4c47d74e24217fcd2b05558d5f300a5d69 /lib | |
parent | 45e7bb7f409d8d4585ef6f8cea76b422e246c2de (diff) | |
parent | 211212f4b3f2897672e3eec26cd073bbcfe85043 (diff) | |
download | nextcloud-server-57e0881a9eb206cb9c3894af600c5ccf4b8b8ff7.tar.gz nextcloud-server-57e0881a9eb206cb9c3894af600c5ccf4b8b8ff7.zip |
Merge pull request #8232 from nextcloud/bugfix/8007/validate-appinfo-against-appstore-schema
Validate appinfo against appstore schema
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/App/AppManager.php | 5 | ||||
-rw-r--r-- | lib/private/App/CodeChecker/InfoChecker.php | 149 |
2 files changed, 63 insertions, 91 deletions
diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 0e921ba1b7f..81037b42613 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -411,6 +411,7 @@ class AppManager implements IAppManager { /** * @inheritdoc + * In case you change this method, also change \OC\App\CodeChecker\InfoChecker::isShipped() */ public function isShipped($appId) { $this->loadShippedJson(); @@ -422,6 +423,10 @@ class AppManager implements IAppManager { return in_array($appId, $alwaysEnabled, true); } + /** + * In case you change this method, also change \OC\App\CodeChecker\InfoChecker::loadShippedJson() + * @throws \Exception + */ private function loadShippedJson() { if ($this->shippedApps === null) { $shippedJson = \OC::$SERVERROOT . '/core/shipped.json'; diff --git a/lib/private/App/CodeChecker/InfoChecker.php b/lib/private/App/CodeChecker/InfoChecker.php index e8791bd7037..f5de6d376d8 100644 --- a/lib/private/App/CodeChecker/InfoChecker.php +++ b/lib/private/App/CodeChecker/InfoChecker.php @@ -23,121 +23,88 @@ namespace OC\App\CodeChecker; -use OC\App\InfoParser; use OC\Hooks\BasicEmitter; +use OCP\App\AppPathNotFoundException; +use OCP\App\IAppManager; class InfoChecker extends BasicEmitter { - /** @var InfoParser */ - private $infoParser; + /** @var string[] */ + private $shippedApps; - private $mandatoryFields = [ - 'author', - 'description', - 'dependencies', - 'id', - 'licence', - 'name', - 'version', - ]; - private $optionalFields = [ - 'bugs', - 'category', - 'default_enable', - 'documentation', - 'namespace', - 'ocsid', - 'public', - 'remote', - 'repository', - 'types', - 'website', - ]; - private $deprecatedFields = [ - 'info', - 'require', - 'requiremax', - 'requiremin', - 'shipped', - 'standalone', - ]; - - public function __construct(InfoParser $infoParser) { - $this->infoParser = $infoParser; - } + /** @var string[] */ + private $alwaysEnabled; /** * @param string $appId * @return array + * @throws \RuntimeException */ - public function analyse($appId) { + public function analyse($appId): array { $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']['nextcloud']['@attributes']['min-version'])) { - $errors[] = [ - 'type' => 'missingRequirement', - 'field' => 'min', - ]; - $this->emit('InfoChecker', 'missingRequirement', ['min']); - } - - if (!isset($info['dependencies']['nextcloud']['@attributes']['max-version'])) { - $errors[] = [ - 'type' => 'missingRequirement', - 'field' => 'max', - ]; - $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; - } + $xml = new \DOMDocument(); + $xml->load($appPath . '/appinfo/info.xml'); - if (in_array($key, $this->optionalFields)) { - $this->emit('InfoChecker', 'optionalFieldFound', [$key, $value]); - continue; + $schema = \OC::$SERVERROOT . '/resources/app-info.xsd'; + try { + if ($this->isShipped($appId)) { + // Shipped apps are allowed to have the public and default_enabled tags + $schema = \OC::$SERVERROOT . '/resources/app-info-shipped.xsd'; } - - 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]); + } catch (\Exception $e) { + // Assume it is not shipped } - foreach ($this->mandatoryFields as $key) { - if(!isset($info[$key])) { - $this->emit('InfoChecker', 'mandatoryFieldMissing', [$key]); + $errors = []; + if (!$xml->schemaValidate($schema)) { + foreach (libxml_get_errors() as $error) { $errors[] = [ - 'type' => 'mandatoryFieldMissing', - 'field' => $key, + 'type' => 'parseError', + 'field' => $error->message, ]; + $this->emit('InfoChecker', 'parseError', [$error->message]); } } - $versionFile = $appPath . '/appinfo/version'; - if (is_file($versionFile)) { - $version = trim(file_get_contents($versionFile)); - $this->emit('InfoChecker', 'migrateVersion', [$version]); - } - return $errors; } + + /** + * This is a copy of \OC\App\AppManager::isShipped(), keep both in sync. + * This method is copied, so the code checker works even when Nextcloud is + * not installed yet. The AppManager requires a database connection, which + * fails in that case. + * + * @param string $appId + * @return bool + * @throws \Exception + */ + protected function isShipped(string $appId): bool { + $this->loadShippedJson(); + return \in_array($appId, $this->shippedApps, true); + } + + /** + * This is a copy of \OC\App\AppManager::loadShippedJson(), keep both in sync + * This method is copied, so the code checker works even when Nextcloud is + * not installed yet. The AppManager requires a database connection, which + * fails in that case. + * + * @throws \Exception + */ + protected 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']; + } + } } |