diff options
Diffstat (limited to 'lib/private/App/AppStore')
-rw-r--r-- | lib/private/App/AppStore/AppNotFoundException.php | 13 | ||||
-rw-r--r-- | lib/private/App/AppStore/Bundles/Bundle.php | 31 | ||||
-rw-r--r-- | lib/private/App/AppStore/Bundles/BundleFetcher.php | 32 | ||||
-rw-r--r-- | lib/private/App/AppStore/Bundles/EducationBundle.php | 26 | ||||
-rw-r--r-- | lib/private/App/AppStore/Bundles/EnterpriseBundle.php | 23 | ||||
-rw-r--r-- | lib/private/App/AppStore/Bundles/GroupwareBundle.php | 24 | ||||
-rw-r--r-- | lib/private/App/AppStore/Bundles/HubBundle.php | 22 | ||||
-rw-r--r-- | lib/private/App/AppStore/Bundles/PublicSectorBundle.php | 36 | ||||
-rw-r--r-- | lib/private/App/AppStore/Bundles/SocialSharingBundle.php | 23 | ||||
-rw-r--r-- | lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php | 100 | ||||
-rw-r--r-- | lib/private/App/AppStore/Fetcher/AppFetcher.php | 69 | ||||
-rw-r--r-- | lib/private/App/AppStore/Fetcher/CategoryFetcher.php | 40 | ||||
-rw-r--r-- | lib/private/App/AppStore/Fetcher/Fetcher.php | 121 | ||||
-rw-r--r-- | lib/private/App/AppStore/Version/Version.php | 34 | ||||
-rw-r--r-- | lib/private/App/AppStore/Version/VersionParser.php | 30 |
15 files changed, 270 insertions, 354 deletions
diff --git a/lib/private/App/AppStore/AppNotFoundException.php b/lib/private/App/AppStore/AppNotFoundException.php new file mode 100644 index 00000000000..79ceebb4423 --- /dev/null +++ b/lib/private/App/AppStore/AppNotFoundException.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OC\App\AppStore; + +class AppNotFoundException extends \Exception { +} diff --git a/lib/private/App/AppStore/Bundles/Bundle.php b/lib/private/App/AppStore/Bundles/Bundle.php index dfc93fdfaa2..1443be81e92 100644 --- a/lib/private/App/AppStore/Bundles/Bundle.php +++ b/lib/private/App/AppStore/Bundles/Bundle.php @@ -1,39 +1,20 @@ <?php + /** - * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author 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/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ 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; + public function __construct( + protected IL10N $l10n, + ) { } /** diff --git a/lib/private/App/AppStore/Bundles/BundleFetcher.php b/lib/private/App/AppStore/Bundles/BundleFetcher.php index 0d2bb61495f..4ff53b0c70b 100644 --- a/lib/private/App/AppStore/Bundles/BundleFetcher.php +++ b/lib/private/App/AppStore/Bundles/BundleFetcher.php @@ -1,36 +1,17 @@ <?php + /** - * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author 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/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\App\AppStore\Bundles; use OCP\IL10N; class BundleFetcher { - private IL10N $l10n; - - public function __construct(IL10N $l10n) { - $this->l10n = $l10n; + public function __construct( + private IL10N $l10n, + ) { } /** @@ -43,6 +24,7 @@ class BundleFetcher { new GroupwareBundle($this->l10n), new SocialSharingBundle($this->l10n), new EducationBundle($this->l10n), + new PublicSectorBundle($this->l10n), ]; } diff --git a/lib/private/App/AppStore/Bundles/EducationBundle.php b/lib/private/App/AppStore/Bundles/EducationBundle.php index 58ffd4f83b8..23681ec7416 100644 --- a/lib/private/App/AppStore/Bundles/EducationBundle.php +++ b/lib/private/App/AppStore/Bundles/EducationBundle.php @@ -1,25 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> - * - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @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/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\App\AppStore\Bundles; @@ -28,7 +11,7 @@ class EducationBundle extends Bundle { * {@inheritDoc} */ public function getName() { - return $this->l10n->t('Education Edition'); + return $this->l10n->t('Education bundle'); } /** @@ -42,6 +25,7 @@ class EducationBundle extends Bundle { 'announcementcenter', 'quota_warning', 'user_saml', + 'whiteboard', ]; } } diff --git a/lib/private/App/AppStore/Bundles/EnterpriseBundle.php b/lib/private/App/AppStore/Bundles/EnterpriseBundle.php index bb64ec391ff..fc2d43e0388 100644 --- a/lib/private/App/AppStore/Bundles/EnterpriseBundle.php +++ b/lib/private/App/AppStore/Bundles/EnterpriseBundle.php @@ -1,25 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> - * - * @author Joas Schilling <coding@schilljs.com> - * @author 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/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\App\AppStore\Bundles; diff --git a/lib/private/App/AppStore/Bundles/GroupwareBundle.php b/lib/private/App/AppStore/Bundles/GroupwareBundle.php index 3a46ada52ad..93fa70268cd 100644 --- a/lib/private/App/AppStore/Bundles/GroupwareBundle.php +++ b/lib/private/App/AppStore/Bundles/GroupwareBundle.php @@ -1,26 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> - * - * @author Bjoern Schiessle <bjoern@schiessle.org> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @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/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\App\AppStore\Bundles; diff --git a/lib/private/App/AppStore/Bundles/HubBundle.php b/lib/private/App/AppStore/Bundles/HubBundle.php index d5d236a1855..354e01e25c2 100644 --- a/lib/private/App/AppStore/Bundles/HubBundle.php +++ b/lib/private/App/AppStore/Bundles/HubBundle.php @@ -3,26 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Julius Härtl <jus@bitgrid.net> - * - * @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/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\App\AppStore\Bundles; diff --git a/lib/private/App/AppStore/Bundles/PublicSectorBundle.php b/lib/private/App/AppStore/Bundles/PublicSectorBundle.php new file mode 100644 index 00000000000..106a6353029 --- /dev/null +++ b/lib/private/App/AppStore/Bundles/PublicSectorBundle.php @@ -0,0 +1,36 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\App\AppStore\Bundles; + +class PublicSectorBundle extends Bundle { + /** + * {@inheritDoc} + */ + public function getName(): string { + return $this->l10n->t('Public sector bundle'); + } + + /** + * {@inheritDoc} + */ + public function getAppIdentifiers(): array { + + return [ + 'files_confidential', + 'forms', + 'collectives', + 'files_antivirus', + 'twofactor_nextcloud_notification', + 'tables', + 'richdocuments', + 'admin_audit', + 'files_retention', + 'whiteboard', + ]; + } + +} diff --git a/lib/private/App/AppStore/Bundles/SocialSharingBundle.php b/lib/private/App/AppStore/Bundles/SocialSharingBundle.php index f823792745b..40f0fb15977 100644 --- a/lib/private/App/AppStore/Bundles/SocialSharingBundle.php +++ b/lib/private/App/AppStore/Bundles/SocialSharingBundle.php @@ -1,25 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> - * - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @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/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\App\AppStore\Bundles; diff --git a/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php b/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php new file mode 100644 index 00000000000..8389e525750 --- /dev/null +++ b/lib/private/App/AppStore/Fetcher/AppDiscoverFetcher.php @@ -0,0 +1,100 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OC\App\AppStore\Fetcher; + +use DateTimeImmutable; +use OC\App\CompareVersion; +use OC\Files\AppData\Factory; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Http\Client\IClientService; +use OCP\IConfig; +use OCP\Support\Subscription\IRegistry; +use Psr\Log\LoggerInterface; + +class AppDiscoverFetcher extends Fetcher { + + public const INVALIDATE_AFTER_SECONDS = 86400; + + public function __construct( + Factory $appDataFactory, + IClientService $clientService, + ITimeFactory $timeFactory, + IConfig $config, + LoggerInterface $logger, + IRegistry $registry, + private CompareVersion $compareVersion, + ) { + parent::__construct( + $appDataFactory, + $clientService, + $timeFactory, + $config, + $logger, + $registry + ); + + $this->fileName = 'discover.json'; + $this->endpointName = 'discover.json'; + } + + /** + * Get the app discover section entries + * + * @param bool $allowUnstable Include also upcoming entries + */ + public function get($allowUnstable = false) { + $entries = parent::get(false); + $now = new DateTimeImmutable(); + + return array_filter($entries, function (array $entry) use ($now, $allowUnstable) { + // Always remove expired entries + if (isset($entry['expiryDate'])) { + try { + $expiryDate = new DateTimeImmutable($entry['expiryDate']); + if ($expiryDate < $now) { + return false; + } + } catch (\Throwable $e) { + // Invalid expiryDate format + return false; + } + } + + // If not include upcoming entries, check for upcoming dates and remove those entries + if (!$allowUnstable && isset($entry['date'])) { + try { + $date = new DateTimeImmutable($entry['date']); + if ($date > $now) { + return false; + } + } catch (\Throwable $e) { + // Invalid date format + return false; + } + } + // Otherwise the entry is not time limited and should stay + return true; + }); + } + + public function getETag(): ?string { + $rootFolder = $this->appData->getFolder('/'); + + try { + $file = $rootFolder->getFile($this->fileName); + $jsonBlob = json_decode($file->getContent(), true); + + if (is_array($jsonBlob) && isset($jsonBlob['ETag'])) { + return (string)$jsonBlob['ETag']; + } + } catch (\Throwable $e) { + // ignore + } + return null; + } +} diff --git a/lib/private/App/AppStore/Fetcher/AppFetcher.php b/lib/private/App/AppStore/Fetcher/AppFetcher.php index 35bec10f5ae..bbf4b00245b 100644 --- a/lib/private/App/AppStore/Fetcher/AppFetcher.php +++ b/lib/private/App/AppStore/Fetcher/AppFetcher.php @@ -1,31 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Jakub Onderka <ahoj@jakubonderka.cz> - * @author Joas Schilling <coding@schilljs.com> - * @author John Molakvoæ <skjnldsv@protonmail.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @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/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\App\AppStore\Fetcher; @@ -39,22 +16,18 @@ use OCP\Support\Subscription\IRegistry; use Psr\Log\LoggerInterface; class AppFetcher extends Fetcher { - /** @var CompareVersion */ - private $compareVersion; - - /** @var IRegistry */ - protected $registry; - /** @var bool */ private $ignoreMaxVersion; - public function __construct(Factory $appDataFactory, - IClientService $clientService, - ITimeFactory $timeFactory, - IConfig $config, - CompareVersion $compareVersion, - LoggerInterface $logger, - IRegistry $registry) { + public function __construct( + Factory $appDataFactory, + IClientService $clientService, + ITimeFactory $timeFactory, + IConfig $config, + private CompareVersion $compareVersion, + LoggerInterface $logger, + protected IRegistry $registry, + ) { parent::__construct( $appDataFactory, $clientService, @@ -64,9 +37,6 @@ class AppFetcher extends Fetcher { $registry ); - $this->compareVersion = $compareVersion; - $this->registry = $registry; - $this->fileName = 'apps.json'; $this->endpointName = 'apps.json'; $this->ignoreMaxVersion = true; @@ -85,7 +55,8 @@ class AppFetcher extends Fetcher { /** @var mixed[] $response */ $response = parent::fetch($ETag, $content); - if (empty($response)) { + if (!isset($response['data']) || $response['data'] === null) { + $this->logger->warning('Response from appstore is invalid, apps could not be retrieved. Try again later.', ['app' => 'appstoreFetcher']); return []; } @@ -99,7 +70,7 @@ class AppFetcher extends Fetcher { foreach ($app['releases'] as $release) { // Exclude all nightly and pre-releases if required if (($allowNightly || $release['isNightly'] === false) - && ($allowPreReleases || strpos($release['version'], '-') === false)) { + && ($allowPreReleases || !str_contains($release['version'], '-'))) { // Exclude all versions not compatible with the current version try { $versionParser = new VersionParser(); @@ -108,8 +79,8 @@ class AppFetcher extends Fetcher { $minServerVersion = $serverVersion->getMinimumVersion(); $maxServerVersion = $serverVersion->getMaximumVersion(); $minFulfilled = $this->compareVersion->isCompatible($ncVersion, $minServerVersion, '>='); - $maxFulfilled = $maxServerVersion !== '' && - $this->compareVersion->isCompatible($ncVersion, $maxServerVersion, '<='); + $maxFulfilled = $maxServerVersion !== '' + && $this->compareVersion->isCompatible($ncVersion, $maxServerVersion, '<='); $isPhpCompatible = true; if (($release['rawPhpVersionSpec'] ?? '*') !== '*') { $phpVersion = $versionParser->getVersion($release['rawPhpVersionSpec']); @@ -180,11 +151,13 @@ class AppFetcher extends Fetcher { $this->ignoreMaxVersion = $ignoreMaxVersion; } - - public function get($allowUnstable = false) { + public function get($allowUnstable = false): array { $allowPreReleases = $allowUnstable || $this->getChannel() === 'beta' || $this->getChannel() === 'daily' || $this->getChannel() === 'git'; $apps = parent::get($allowPreReleases); + if (empty($apps)) { + return []; + } $allowList = $this->config->getSystemValue('appsallowlist'); // If the admin specified a allow list, filter apps from the appstore diff --git a/lib/private/App/AppStore/Fetcher/CategoryFetcher.php b/lib/private/App/AppStore/Fetcher/CategoryFetcher.php index afe051e6281..d7857d41bee 100644 --- a/lib/private/App/AppStore/Fetcher/CategoryFetcher.php +++ b/lib/private/App/AppStore/Fetcher/CategoryFetcher.php @@ -1,28 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @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/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\App\AppStore\Fetcher; @@ -34,12 +14,14 @@ use OCP\Support\Subscription\IRegistry; use Psr\Log\LoggerInterface; class CategoryFetcher extends Fetcher { - public function __construct(Factory $appDataFactory, - IClientService $clientService, - ITimeFactory $timeFactory, - IConfig $config, - LoggerInterface $logger, - IRegistry $registry) { + public function __construct( + Factory $appDataFactory, + IClientService $clientService, + ITimeFactory $timeFactory, + IConfig $config, + LoggerInterface $logger, + IRegistry $registry, + ) { parent::__construct( $appDataFactory, $clientService, diff --git a/lib/private/App/AppStore/Fetcher/Fetcher.php b/lib/private/App/AppStore/Fetcher/Fetcher.php index 0eb089bbdc2..24876675d60 100644 --- a/lib/private/App/AppStore/Fetcher/Fetcher.php +++ b/lib/private/App/AppStore/Fetcher/Fetcher.php @@ -1,32 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> - * - * @author Daniel Kesselberg <mail@danielkesselberg.de> - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * @author John Molakvoæ <skjnldsv@protonmail.com> - * @author Julius Härtl <jus@bitgrid.net> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Steffen Lindner <mail@steffen-lindner.de> - * - * @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/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\App\AppStore\Fetcher; @@ -38,47 +14,38 @@ use OCP\Files\IAppData; use OCP\Files\NotFoundException; use OCP\Http\Client\IClientService; use OCP\IConfig; +use OCP\Server; +use OCP\ServerVersion; use OCP\Support\Subscription\IRegistry; use Psr\Log\LoggerInterface; abstract class Fetcher { public const INVALIDATE_AFTER_SECONDS = 3600; + public const INVALIDATE_AFTER_SECONDS_UNSTABLE = 900; public const RETRY_AFTER_FAILURE_SECONDS = 300; + public const APP_STORE_URL = 'https://apps.nextcloud.com/api/v1'; /** @var IAppData */ protected $appData; - /** @var IClientService */ - protected $clientService; - /** @var ITimeFactory */ - protected $timeFactory; - /** @var IConfig */ - protected $config; - /** @var LoggerInterface */ - protected $logger; - /** @var IRegistry */ - protected $registry; /** @var string */ protected $fileName; /** @var string */ protected $endpointName; - /** @var string */ - protected $version; - /** @var string */ - protected $channel; - - public function __construct(Factory $appDataFactory, - IClientService $clientService, - ITimeFactory $timeFactory, - IConfig $config, - LoggerInterface $logger, - IRegistry $registry) { + /** @var ?string */ + protected $version = null; + /** @var ?string */ + protected $channel = null; + + public function __construct( + Factory $appDataFactory, + protected IClientService $clientService, + protected ITimeFactory $timeFactory, + protected IConfig $config, + protected LoggerInterface $logger, + protected IRegistry $registry, + ) { $this->appData = $appDataFactory->get('appstore'); - $this->clientService = $clientService; - $this->timeFactory = $timeFactory; - $this->config = $config; - $this->logger = $logger; - $this->registry = $registry; } /** @@ -89,7 +56,7 @@ abstract class Fetcher { * * @return array */ - protected function fetch($ETag, $content) { + protected function fetch($ETag, $content, $allowUnstable = false) { $appstoreenabled = $this->config->getSystemValueBool('appstoreenabled', true); if ((int)$this->config->getAppValue('settings', 'appstore-fetcher-lastFailure', '0') > time() - self::RETRY_AFTER_FAILURE_SECONDS) { return []; @@ -109,10 +76,13 @@ abstract class Fetcher { ]; } - // If we have a valid subscription key, send it to the appstore - $subscriptionKey = $this->config->getAppValue('support', 'subscription_key'); - if ($this->registry->delegateHasValidSubscription() && $subscriptionKey) { - $options['headers']['X-NC-Subscription-Key'] = $subscriptionKey; + if ($this->config->getSystemValueString('appstoreurl', self::APP_STORE_URL) === self::APP_STORE_URL) { + // If we have a valid subscription key, send it to the appstore + $subscriptionKey = $this->config->getAppValue('support', 'subscription_key'); + if ($this->registry->delegateHasValidSubscription() && $subscriptionKey) { + $options['headers'] ??= []; + $options['headers']['X-NC-Subscription-Key'] = $subscriptionKey; + } } $client = $this->clientService->newClient(); @@ -120,7 +90,8 @@ abstract class Fetcher { $response = $client->get($this->getEndpoint(), $options); } catch (ConnectException $e) { $this->config->setAppValue('settings', 'appstore-fetcher-lastFailure', (string)time()); - throw $e; + $this->logger->error('Failed to connect to the app store', ['exception' => $e]); + return []; } $responseJson = []; @@ -142,16 +113,18 @@ abstract class Fetcher { } /** - * Returns the array with the categories on the appstore server + * Returns the array with the entries on the appstore server * * @param bool [$allowUnstable] Allow unstable releases * @return array */ public function get($allowUnstable = false) { $appstoreenabled = $this->config->getSystemValueBool('appstoreenabled', true); - $internetavailable = $this->config->getSystemValue('has_internet_connection', true); + $internetavailable = $this->config->getSystemValueBool('has_internet_connection', true); + $isDefaultAppStore = $this->config->getSystemValueString('appstoreurl', self::APP_STORE_URL) === self::APP_STORE_URL; - if (!$appstoreenabled || !$internetavailable) { + if (!$appstoreenabled || (!$internetavailable && $isDefaultAppStore)) { + $this->logger->info('AppStore is disabled or this instance has no Internet connection to access the default app store', ['app' => 'appstoreFetcher']); return []; } @@ -165,12 +138,17 @@ abstract class Fetcher { $file = $rootFolder->getFile($this->fileName); $jsonBlob = json_decode($file->getContent(), true); - // Always get latests apps info if $allowUnstable - if (!$allowUnstable && is_array($jsonBlob)) { + 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 3600 seconds request the files new - if ((int)$jsonBlob['timestamp'] > ($this->timeFactory->getTime() - self::INVALIDATE_AFTER_SECONDS)) { + $invalidateAfterSeconds = self::INVALIDATE_AFTER_SECONDS; + + if ($allowUnstable) { + $invalidateAfterSeconds = self::INVALIDATE_AFTER_SECONDS_UNSTABLE; + } + + if ((int)$jsonBlob['timestamp'] > ($this->timeFactory->getTime() - $invalidateAfterSeconds)) { return $jsonBlob['data']; } @@ -189,15 +167,10 @@ abstract class Fetcher { try { $responseJson = $this->fetch($ETag, $content, $allowUnstable); - if (empty($responseJson)) { + if (empty($responseJson) || empty($responseJson['data'])) { return []; } - // Don't store the apps request file - if ($allowUnstable) { - return $responseJson['data']; - } - $file->putContent(json_encode($responseJson)); return json_decode($file->getContent(), true)['data']; } catch (ConnectException $e) { @@ -218,7 +191,7 @@ abstract class Fetcher { */ protected function getVersion() { if ($this->version === null) { - $this->version = $this->config->getSystemValue('version', '0.0.0'); + $this->version = $this->config->getSystemValueString('version', '0.0.0'); } return $this->version; } @@ -237,7 +210,7 @@ abstract class Fetcher { */ protected function getChannel() { if ($this->channel === null) { - $this->channel = \OC_Util::getChannel(); + $this->channel = Server::get(ServerVersion::class)->getChannel(); } return $this->channel; } @@ -251,6 +224,6 @@ abstract class Fetcher { } protected function getEndpoint(): string { - return $this->config->getSystemValue('appstoreurl', 'https://apps.nextcloud.com/api/v1') . '/' . $this->endpointName; + return $this->config->getSystemValueString('appstoreurl', 'https://apps.nextcloud.com/api/v1') . '/' . $this->endpointName; } } diff --git a/lib/private/App/AppStore/Version/Version.php b/lib/private/App/AppStore/Version/Version.php index d41ca1770f0..2d169a291f1 100644 --- a/lib/private/App/AppStore/Version/Version.php +++ b/lib/private/App/AppStore/Version/Version.php @@ -1,40 +1,20 @@ <?php + /** - * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> - * - * @author 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/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ 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; + public function __construct( + private string $minVersion, + private string $maxVersion, + ) { } /** diff --git a/lib/private/App/AppStore/Version/VersionParser.php b/lib/private/App/AppStore/Version/VersionParser.php index 6a369b1cb6e..8976f28837f 100644 --- a/lib/private/App/AppStore/Version/VersionParser.php +++ b/lib/private/App/AppStore/Version/VersionParser.php @@ -1,26 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @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/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\App\AppStore\Version; @@ -54,9 +36,9 @@ class VersionParser { // 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] : ''; + $firstVersion = $versionElements[0] ?? ''; $firstVersionNumber = substr($firstVersion, 2); - $secondVersion = isset($versionElements[1]) ? $versionElements[1] : ''; + $secondVersion = $versionElements[1] ?? ''; $secondVersionNumber = substr($secondVersion, 2); switch (count($versionElements)) { @@ -64,7 +46,7 @@ class VersionParser { if (!$this->isValidVersionString($firstVersionNumber)) { break; } - if (strpos($firstVersion, '>') === 0) { + if (str_starts_with($firstVersion, '>')) { return new Version($firstVersionNumber, ''); } return new Version('', $firstVersionNumber); |