From 73b07ec1d36119e20df8ff47aadd4fbe51a902a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6=20=28skjnldsv=29?= Date: Wed, 20 Aug 2025 10:28:25 +0200 Subject: [PATCH 1/2] chore: update psalm workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ (skjnldsv) [skip ci] --- .github/workflows/psalm.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 7be48f26..3d29b70e 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -2,6 +2,9 @@ # # https://github.com/nextcloud/.github # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization +# +# SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: MIT name: Static analysis @@ -17,6 +20,9 @@ concurrency: group: psalm-${{ github.head_ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read + jobs: static-analysis: runs-on: ubuntu-latest @@ -32,6 +38,8 @@ jobs: php-version: 8.1 coverage: none ini-file: development + # Temporary workaround for missing pcntl_* in PHP 8.3 + ini-values: disable_functions= env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -39,4 +47,4 @@ jobs: run: composer i - name: Run coding standards check - run: composer run psalm + run: composer run psalm -- --threads=1 --monochrome --no-progress --output-format=github From b415c5a26928abda040fc720201a3f32490435f7 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Thu, 10 Jul 2025 10:48:29 +0200 Subject: [PATCH 2/2] feat: allow to provide manual URL Signed-off-by: skjnldsv --- index.php | 35 ++++++++++++++++---- lib/UpdateCommand.php | 28 ++++++++++------ lib/Updater.php | 35 ++++++++++++++++---- updater.phar | Bin 757575 -> 759922 bytes vendor/autoload.php | 5 +-- vendor/composer/InstalledVersions.php | 45 +++++++++++++++++++++++--- vendor/composer/installed.php | 4 +-- vendor/composer/platform_check.php | 5 ++- 8 files changed, 121 insertions(+), 36 deletions(-) diff --git a/index.php b/index.php index 24aad88c..4a16553e 100644 --- a/index.php +++ b/index.php @@ -553,11 +553,9 @@ private function getUpdateServerResponse() { * * @throws \Exception */ - public function downloadUpdate() { + public function downloadUpdate(?string $url = null) { $this->silentLog('[info] downloadUpdate()'); - $response = $this->getUpdateServerResponse(); - $storageLocation = $this->getUpdateDirectoryLocation() . '/updater-'.$this->getConfigOption('instanceid') . '/downloads/'; if (file_exists($storageLocation)) { $this->silentLog('[info] storage location exists'); @@ -568,8 +566,26 @@ public function downloadUpdate() { throw new \Exception('Could not mkdir storage location'); } - $fp = fopen($storageLocation . basename($response['url']), 'w+'); - $ch = curl_init($response['url']); + $downloadURL = ''; + if ($url) { + // If a URL is provided, use it directly + $downloadURL = $url; + } else { + // Otherwise, get the download URLs from the update server + $response = $this->getUpdateServerResponse(); + + if (!isset($response['url']) || !is_string($response['url'])) { + throw new \Exception('Response from update server is missing url'); + } + $downloadURL = $response['url']; + } + + if (!$downloadURL) { + throw new \Exception('No download URL provided or available from update server'); + } + + $fp = fopen($storageLocation . basename($downloadURL), 'w+'); + $ch = curl_init($downloadURL); curl_setopt_array($ch, [ CURLOPT_FILE => $fp, CURLOPT_USERAGENT => 'Nextcloud Updater', @@ -611,7 +627,7 @@ public function downloadUpdate() { $message .= ' - curl error message: ' . $curlErrorMessage; } - $message .= ' - URL: ' . htmlentities($response['url']); + $message .= ' - URL: ' . htmlentities($downloadURL); throw new \Exception($message); } @@ -645,7 +661,7 @@ private function getDownloadedFilePath() { * * @throws \Exception */ - public function verifyIntegrity() { + public function verifyIntegrity(?string $urlOverride = null): void { $this->silentLog('[info] verifyIntegrity()'); if ($this->getCurrentReleaseChannel() === 'daily') { @@ -653,6 +669,11 @@ public function verifyIntegrity() { return; } + if ($urlOverride) { + $this->silentLog('[info] custom download url provided, cannot verify signature'); + return; + } + $response = $this->getUpdateServerResponse(); if (empty($response['signature'])) { throw new \Exception('No signature specified for defined update'); diff --git a/lib/UpdateCommand.php b/lib/UpdateCommand.php index 9a438cd9..65aedc73 100644 --- a/lib/UpdateCommand.php +++ b/lib/UpdateCommand.php @@ -41,6 +41,7 @@ class UpdateCommand extends Command { protected $skipBackup = false; protected bool $skipUpgrade = false; + protected string $urlOverride = ''; /** @var array strings of text for stages of updater */ protected $checkTexts = [ @@ -65,7 +66,8 @@ protected function configure() { ->setDescription('Updates the code of an Nextcloud instance') ->setHelp("This command fetches the latest code that is announced via the updater server and safely replaces the existing code with the new one.") ->addOption('no-backup', null, InputOption::VALUE_NONE, 'Skip backup of current Nextcloud version') - ->addOption('no-upgrade', null, InputOption::VALUE_NONE, "Don't automatically run occ upgrade"); + ->addOption('no-upgrade', null, InputOption::VALUE_NONE, "Don't automatically run occ upgrade") + ->addOption('url', null, InputOption::VALUE_OPTIONAL, 'The URL of the Nextcloud release to download'); } public static function getUpdaterVersion(): string { @@ -78,8 +80,9 @@ public static function getUpdaterVersion(): string { } protected function execute(InputInterface $input, OutputInterface $output) { - $this->skipBackup = $input->getOption('no-backup'); - $this->skipUpgrade = $input->getOption('no-upgrade'); + $this->skipBackup = (bool)$input->getOption('no-backup'); + $this->skipUpgrade = (bool)$input->getOption('no-upgrade'); + $this->urlOverride = (string)$input->getOption('url'); $version = static::getUpdaterVersion(); $output->writeln('Nextcloud Updater - version: ' . $version); @@ -152,7 +155,12 @@ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('Current version is ' . $this->updater->getCurrentVersion() . '.'); // needs to be called that early because otherwise updateAvailable() returns false - $updateString = $this->updater->checkForUpdate(); + if ($this->urlOverride) { + $this->updater->log('[info] Using URL override: ' . $this->urlOverride); + $updateString = 'Update check forced with URL override: ' . $this->urlOverride; + } else { + $updateString = $this->updater->checkForUpdate(); + } $output->writeln(''); @@ -165,9 +173,11 @@ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln(''); - if (!$this->updater->updateAvailable() && $stepNumber === 0) { - $output->writeln('Nothing to do.'); - return 0; + if (!$this->urlOverride) { + if (!$this->updater->updateAvailable() && $stepNumber === 0) { + $output->writeln('Nothing to do.'); + return 0; + } } $questionText = 'Start update'; @@ -374,10 +384,10 @@ protected function executeStep($step) { } break; case 4: - $this->updater->downloadUpdate(); + $this->updater->downloadUpdate($this->urlOverride); break; case 5: - $this->updater->verifyIntegrity(); + $this->updater->verifyIntegrity($this->urlOverride); break; case 6: $this->updater->extractDownload(); diff --git a/lib/Updater.php b/lib/Updater.php index 06f65e8b..16e3a721 100644 --- a/lib/Updater.php +++ b/lib/Updater.php @@ -517,11 +517,9 @@ private function getUpdateServerResponse() { * * @throws \Exception */ - public function downloadUpdate() { + public function downloadUpdate(?string $url = null) { $this->silentLog('[info] downloadUpdate()'); - $response = $this->getUpdateServerResponse(); - $storageLocation = $this->getUpdateDirectoryLocation() . '/updater-'.$this->getConfigOption('instanceid') . '/downloads/'; if (file_exists($storageLocation)) { $this->silentLog('[info] storage location exists'); @@ -532,8 +530,26 @@ public function downloadUpdate() { throw new \Exception('Could not mkdir storage location'); } - $fp = fopen($storageLocation . basename($response['url']), 'w+'); - $ch = curl_init($response['url']); + $downloadURL = ''; + if ($url) { + // If a URL is provided, use it directly + $downloadURL = $url; + } else { + // Otherwise, get the download URLs from the update server + $response = $this->getUpdateServerResponse(); + + if (!isset($response['url']) || !is_string($response['url'])) { + throw new \Exception('Response from update server is missing url'); + } + $downloadURL = $response['url']; + } + + if (!$downloadURL) { + throw new \Exception('No download URL provided or available from update server'); + } + + $fp = fopen($storageLocation . basename($downloadURL), 'w+'); + $ch = curl_init($downloadURL); curl_setopt_array($ch, [ CURLOPT_FILE => $fp, CURLOPT_USERAGENT => 'Nextcloud Updater', @@ -575,7 +591,7 @@ public function downloadUpdate() { $message .= ' - curl error message: ' . $curlErrorMessage; } - $message .= ' - URL: ' . htmlentities($response['url']); + $message .= ' - URL: ' . htmlentities($downloadURL); throw new \Exception($message); } @@ -609,7 +625,7 @@ private function getDownloadedFilePath() { * * @throws \Exception */ - public function verifyIntegrity() { + public function verifyIntegrity(?string $urlOverride = null): void { $this->silentLog('[info] verifyIntegrity()'); if ($this->getCurrentReleaseChannel() === 'daily') { @@ -617,6 +633,11 @@ public function verifyIntegrity() { return; } + if ($urlOverride) { + $this->silentLog('[info] custom download url provided, cannot verify signature'); + return; + } + $response = $this->getUpdateServerResponse(); if (empty($response['signature'])) { throw new \Exception('No signature specified for defined update'); diff --git a/updater.phar b/updater.phar index e406bfe031cace82582e83c2a23bd2ee5477896b..7f43af1091f8b3a568c529931602063e9a99dda3 100755 GIT binary patch delta 8190 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 IvPotC2bE*`YXATM delta 6501 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 diff --git a/vendor/autoload.php b/vendor/autoload.php index e97f2aed..f52071e9 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -14,10 +14,7 @@ echo $err; } } - trigger_error( - $err, - E_USER_ERROR - ); + throw new RuntimeException($err); } require_once __DIR__ . '/composer/autoload_real.php'; diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php index 51e734a7..2052022f 100644 --- a/vendor/composer/InstalledVersions.php +++ b/vendor/composer/InstalledVersions.php @@ -26,12 +26,23 @@ */ class InstalledVersions { + /** + * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to + * @internal + */ + private static $selfDir = null; + /** * @var mixed[]|null * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null */ private static $installed; + /** + * @var bool + */ + private static $installedIsLocalDir; + /** * @var bool|null */ @@ -309,6 +320,24 @@ public static function reload($data) { self::$installed = $data; self::$installedByVendor = array(); + + // when using reload, we disable the duplicate protection to ensure that self::$installed data is + // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, + // so we have to assume it does not, and that may result in duplicate data being returned when listing + // all installed packages for example + self::$installedIsLocalDir = false; + } + + /** + * @return string + */ + private static function getSelfDir() + { + if (self::$selfDir === null) { + self::$selfDir = strtr(__DIR__, '\\', '/'); + } + + return self::$selfDir; } /** @@ -322,19 +351,27 @@ private static function getInstalled() } $installed = array(); + $copiedLocalDir = false; if (self::$canGetVendors) { + $selfDir = self::getSelfDir(); foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + $vendorDir = strtr($vendorDir, '\\', '/'); if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ $required = require $vendorDir.'/composer/installed.php'; - $installed[] = self::$installedByVendor[$vendorDir] = $required; - if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { - self::$installed = $installed[count($installed) - 1]; + self::$installedByVendor[$vendorDir] = $required; + $installed[] = $required; + if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { + self::$installed = $required; + self::$installedIsLocalDir = true; } } + if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { + $copiedLocalDir = true; + } } } @@ -350,7 +387,7 @@ private static function getInstalled() } } - if (self::$installed !== array()) { + if (self::$installed !== array() && !$copiedLocalDir) { $installed[] = self::$installed; } diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index de5be70d..d0a887f5 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => 'b3b17cf837de98718ef2bc2277fbc1db24f4288f', + 'reference' => '1ed21d3dfe750ed9fc1ebe42927b1a0955a42c27', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -13,7 +13,7 @@ '__root__' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => 'b3b17cf837de98718ef2bc2277fbc1db24f4288f', + 'reference' => '1ed21d3dfe750ed9fc1ebe42927b1a0955a42c27', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php index 580fa960..d2225c7d 100644 --- a/vendor/composer/platform_check.php +++ b/vendor/composer/platform_check.php @@ -19,8 +19,7 @@ echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; } } - trigger_error( - 'Composer detected issues in your platform: ' . implode(' ', $issues), - E_USER_ERROR + throw new \RuntimeException( + 'Composer detected issues in your platform: ' . implode(' ', $issues) ); }