Skip to content

Commit 666f5e1

Browse files
committed
feat: allow to provide manual URL
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
1 parent 57ea0c7 commit 666f5e1

File tree

6 files changed

+83
-65
lines changed

6 files changed

+83
-65
lines changed

index.php

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -572,27 +572,35 @@ private function getUpdateServerResponse(): array {
572572
*
573573
* @throws \Exception
574574
*/
575-
public function downloadUpdate(): void {
575+
public function downloadUpdate(?string $url = null): void {
576576
$this->silentLog('[info] downloadUpdate()');
577577

578-
$response = $this->getUpdateServerResponse();
578+
$downloadURL = '';
579+
if ($url) {
580+
// If a URL is provided, use it directly
581+
$downloadURL = $url;
582+
} else {
583+
// Otherwise, get the download URLs from the update server
584+
$response = $this->getUpdateServerResponse();
579585

580-
$storageLocation = $this->getUpdateDirectoryLocation() . '/updater-'.$this->getConfigOptionMandatoryString('instanceid') . '/downloads/';
581-
if (file_exists($storageLocation)) {
582-
$this->silentLog('[info] storage location exists');
583-
$this->recursiveDelete($storageLocation);
584-
}
585-
$state = mkdir($storageLocation, 0750, true);
586-
if ($state === false) {
587-
throw new \Exception('Could not mkdir storage location');
588-
}
586+
$storageLocation = $this->getUpdateDirectoryLocation() . '/updater-'.$this->getConfigOptionMandatoryString('instanceid') . '/downloads/';
587+
if (file_exists($storageLocation)) {
588+
$this->silentLog('[info] storage location exists');
589+
$this->recursiveDelete($storageLocation);
590+
}
591+
$state = mkdir($storageLocation, 0750, true);
592+
if ($state === false) {
593+
throw new \Exception('Could not mkdir storage location');
594+
}
589595

590-
if (!isset($response['url']) || !is_string($response['url'])) {
591-
throw new \Exception('Response from update server is missing url');
596+
if (!isset($response['url']) || !is_string($response['url'])) {
597+
throw new \Exception('Response from update server is missing url');
598+
}
599+
$downloadURL = $response['url'];
592600
}
593601

594-
$fp = fopen($storageLocation . basename($response['url']), 'w+');
595-
$ch = curl_init($response['url']);
602+
$fp = fopen($storageLocation . basename($downloadURL), 'w+');
603+
$ch = curl_init($downloadURL);
596604
curl_setopt_array($ch, [
597605
CURLOPT_FILE => $fp,
598606
CURLOPT_USERAGENT => 'Nextcloud Updater',
@@ -636,7 +644,7 @@ public function downloadUpdate(): void {
636644
$message .= ' - curl error message: ' . $curlErrorMessage;
637645
}
638646

639-
$message .= ' - URL: ' . htmlentities($response['url']);
647+
$message .= ' - URL: ' . htmlentities($downloadURL);
640648

641649
throw new \Exception($message);
642650
}
@@ -669,14 +677,19 @@ private function getDownloadedFilePath(): string {
669677
*
670678
* @throws \Exception
671679
*/
672-
public function verifyIntegrity(): void {
680+
public function verifyIntegrity(?string $urlOverride = null): void {
673681
$this->silentLog('[info] verifyIntegrity()');
674682

675683
if ($this->getCurrentReleaseChannel() === 'daily') {
676684
$this->silentLog('[info] current channel is "daily" which is not signed. Skipping verification.');
677685
return;
678686
}
679687

688+
if ($urlOverride) {
689+
$this->silentLog('[info] custom download url provided, cannot verify signature');
690+
return;
691+
}
692+
680693
$response = $this->getUpdateServerResponse();
681694
if (empty($response['signature'])) {
682695
throw new \Exception('No signature specified for defined update');

lib/UpdateCommand.php

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class UpdateCommand extends Command {
3939
protected bool $shouldStop = false;
4040
protected bool $skipBackup = false;
4141
protected bool $skipUpgrade = false;
42+
protected string $urlOverride = '';
4243

4344
/** @var list<string> strings of text for stages of updater */
4445
protected array $checkTexts = [
@@ -63,7 +64,8 @@ protected function configure(): void {
6364
->setDescription('Updates the code of an Nextcloud instance')
6465
->setHelp("This command fetches the latest code that is announced via the updater server and safely replaces the existing code with the new one.")
6566
->addOption('no-backup', null, InputOption::VALUE_NONE, 'Skip backup of current Nextcloud version')
66-
->addOption('no-upgrade', null, InputOption::VALUE_NONE, "Don't automatically run occ upgrade");
67+
->addOption('no-upgrade', null, InputOption::VALUE_NONE, "Don't automatically run occ upgrade")
68+
->addOption('url', null, InputOption::VALUE_OPTIONAL, 'The URL of the Nextcloud release to download');
6769
}
6870

6971
public static function getUpdaterVersion(): string {
@@ -78,6 +80,7 @@ public static function getUpdaterVersion(): string {
7880
protected function execute(InputInterface $input, OutputInterface $output) {
7981
$this->skipBackup = (bool)$input->getOption('no-backup');
8082
$this->skipUpgrade = (bool)$input->getOption('no-upgrade');
83+
$this->urlOverride = (string)$input->getOption('url');
8184

8285
$version = static::getUpdaterVersion();
8386
$output->writeln('Nextcloud Updater - version: ' . $version);
@@ -151,7 +154,12 @@ protected function execute(InputInterface $input, OutputInterface $output) {
151154
$output->writeln('Current version is ' . $this->updater->getCurrentVersion() . '.');
152155

153156
// needs to be called that early because otherwise updateAvailable() returns false
154-
$updateString = $this->updater->checkForUpdate();
157+
if ($this->urlOverride) {
158+
$this->updater->log('[info] Using URL override: ' . $this->urlOverride);
159+
$updateString = 'Update check forced with URL override: ' . $this->urlOverride;
160+
} else {
161+
$updateString = $this->updater->checkForUpdate();
162+
}
155163

156164
$output->writeln('');
157165

@@ -164,9 +172,11 @@ protected function execute(InputInterface $input, OutputInterface $output) {
164172

165173
$output->writeln('');
166174

167-
if (!$this->updater->updateAvailable() && $stepNumber === 0) {
168-
$output->writeln('Nothing to do.');
169-
return 0;
175+
if (!$this->urlOverride) {
176+
if (!$this->updater->updateAvailable() && $stepNumber === 0) {
177+
$output->writeln('Nothing to do.');
178+
return 0;
179+
}
170180
}
171181

172182
$questionText = 'Start update';
@@ -378,10 +388,10 @@ protected function executeStep(int $step): array {
378388
}
379389
break;
380390
case 4:
381-
$this->updater->downloadUpdate();
391+
$this->updater->downloadUpdate($this->urlOverride);
382392
break;
383393
case 5:
384-
$this->updater->verifyIntegrity();
394+
$this->updater->verifyIntegrity($this->urlOverride);
385395
break;
386396
case 6:
387397
$this->updater->extractDownload();

lib/Updater.php

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,8 @@
33
declare(strict_types=1);
44

55
/**
6-
* @copyright Copyright (c) 2016-2017 Lukas Reschke <lukas@statuscode.ch>
7-
* @copyright Copyright (c) 2016 Morris Jobke <hey@morrisjobke.de>
8-
* @copyright Copyright (c) 2018 Jonas Sulzer <jonas@violoncello.ch>
9-
*
10-
* @license GNU AGPL version 3 or any later version
11-
*
12-
* This program is free software: you can redistribute it and/or modify
13-
* it under the terms of the GNU Affero General Public License as
14-
* published by the Free Software Foundation, either version 3 of the
15-
* License, or (at your option) any later version.
16-
*
17-
* This program is distributed in the hope that it will be useful,
18-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20-
* GNU Affero General Public License for more details.
21-
*
22-
* You should have received a copy of the GNU Affero General Public License
23-
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24-
*
6+
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
258
*/
269

2710
namespace NC\Updater;
@@ -534,27 +517,35 @@ private function getUpdateServerResponse(): array {
534517
*
535518
* @throws \Exception
536519
*/
537-
public function downloadUpdate(): void {
520+
public function downloadUpdate(?string $url = null): void {
538521
$this->silentLog('[info] downloadUpdate()');
539522

540-
$response = $this->getUpdateServerResponse();
523+
$downloadURL = '';
524+
if ($url) {
525+
// If a URL is provided, use it directly
526+
$downloadURL = $url;
527+
} else {
528+
// Otherwise, get the download URLs from the update server
529+
$response = $this->getUpdateServerResponse();
541530

542-
$storageLocation = $this->getUpdateDirectoryLocation() . '/updater-'.$this->getConfigOptionMandatoryString('instanceid') . '/downloads/';
543-
if (file_exists($storageLocation)) {
544-
$this->silentLog('[info] storage location exists');
545-
$this->recursiveDelete($storageLocation);
546-
}
547-
$state = mkdir($storageLocation, 0750, true);
548-
if ($state === false) {
549-
throw new \Exception('Could not mkdir storage location');
550-
}
531+
$storageLocation = $this->getUpdateDirectoryLocation() . '/updater-'.$this->getConfigOptionMandatoryString('instanceid') . '/downloads/';
532+
if (file_exists($storageLocation)) {
533+
$this->silentLog('[info] storage location exists');
534+
$this->recursiveDelete($storageLocation);
535+
}
536+
$state = mkdir($storageLocation, 0750, true);
537+
if ($state === false) {
538+
throw new \Exception('Could not mkdir storage location');
539+
}
551540

552-
if (!isset($response['url']) || !is_string($response['url'])) {
553-
throw new \Exception('Response from update server is missing url');
541+
if (!isset($response['url']) || !is_string($response['url'])) {
542+
throw new \Exception('Response from update server is missing url');
543+
}
544+
$downloadURL = $response['url'];
554545
}
555546

556-
$fp = fopen($storageLocation . basename($response['url']), 'w+');
557-
$ch = curl_init($response['url']);
547+
$fp = fopen($storageLocation . basename($downloadURL), 'w+');
548+
$ch = curl_init($downloadURL);
558549
curl_setopt_array($ch, [
559550
CURLOPT_FILE => $fp,
560551
CURLOPT_USERAGENT => 'Nextcloud Updater',
@@ -598,7 +589,7 @@ public function downloadUpdate(): void {
598589
$message .= ' - curl error message: ' . $curlErrorMessage;
599590
}
600591

601-
$message .= ' - URL: ' . htmlentities($response['url']);
592+
$message .= ' - URL: ' . htmlentities($downloadURL);
602593

603594
throw new \Exception($message);
604595
}
@@ -631,14 +622,19 @@ private function getDownloadedFilePath(): string {
631622
*
632623
* @throws \Exception
633624
*/
634-
public function verifyIntegrity(): void {
625+
public function verifyIntegrity(?string $urlOverride = null): void {
635626
$this->silentLog('[info] verifyIntegrity()');
636627

637628
if ($this->getCurrentReleaseChannel() === 'daily') {
638629
$this->silentLog('[info] current channel is "daily" which is not signed. Skipping verification.');
639630
return;
640631
}
641632

633+
if ($urlOverride) {
634+
$this->silentLog('[info] custom download url provided, cannot verify signature');
635+
return;
636+
}
637+
642638
$response = $this->getUpdateServerResponse();
643639
if (empty($response['signature'])) {
644640
throw new \Exception('No signature specified for defined update');

updater.phar

32 Bytes
Binary file not shown.

vendor/composer/installed.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'name' => '__root__',
44
'pretty_version' => 'dev-master',
55
'version' => 'dev-master',
6-
'reference' => '9adb775ee0ca02d832347ddfea2b4c248f2805bc',
6+
'reference' => '088152d70d870f9021ea6231578e59d7dbbd6fd0',
77
'type' => 'library',
88
'install_path' => __DIR__ . '/../../',
99
'aliases' => array(),
@@ -13,7 +13,7 @@
1313
'__root__' => array(
1414
'pretty_version' => 'dev-master',
1515
'version' => 'dev-master',
16-
'reference' => '9adb775ee0ca02d832347ddfea2b4c248f2805bc',
16+
'reference' => '088152d70d870f9021ea6231578e59d7dbbd6fd0',
1717
'type' => 'library',
1818
'install_path' => __DIR__ . '/../../',
1919
'aliases' => array(),

vendor/composer/platform_check.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
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;
2020
}
2121
}
22-
trigger_error(
23-
'Composer detected issues in your platform: ' . implode(' ', $issues),
24-
E_USER_ERROR
22+
throw new \RuntimeException(
23+
'Composer detected issues in your platform: ' . implode(' ', $issues)
2524
);
2625
}

0 commit comments

Comments
 (0)