Skip to content

Commit 02c3af1

Browse files
Altahrimbackportbot[bot]
authored andcommitted
feat(signature): allow to provide custom signature
feat(signature): allow to provide custom signature Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com> [skip ci]
1 parent a8c857b commit 02c3af1

3 files changed

Lines changed: 59 additions & 40 deletions

File tree

index.php

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -615,11 +615,11 @@ private function getUpdateServerResponse(): array {
615615
*
616616
* @throws \Exception
617617
*/
618-
public function downloadUpdate(string $url = '', ?Closure $downloadProgress = null): void {
618+
public function downloadUpdate(string $urlOverride = '', ?Closure $downloadProgress = null): void {
619619
$this->silentLog('[info] downloadUpdate()');
620620
$this->downloadProgress = $downloadProgress;
621621

622-
$downloadURLs = $url !== '' ? [$url] : $this->getDownloadURLs();
622+
$downloadURLs = $urlOverride !== '' ? [$urlOverride] : $this->getDownloadURLs();
623623

624624
$this->silentLog('[info] will try to download archive from: ' . implode(', ', $downloadURLs));
625625

@@ -641,10 +641,10 @@ public function downloadUpdate(string $url = '', ?Closure $downloadProgress = nu
641641
}
642642
}
643643

644-
foreach ($downloadURLs as $url) {
644+
foreach ($downloadURLs as $urlOverride) {
645645
$this->previousProgress = 0;
646-
$saveLocation = $storageLocation . basename((string)$url);
647-
if ($this->downloadArchive($url, $saveLocation)) {
646+
$saveLocation = $storageLocation . basename((string)$urlOverride);
647+
if ($this->downloadArchive($urlOverride, $saveLocation)) {
648648
return;
649649
}
650650
}
@@ -830,26 +830,21 @@ private function getDownloadedFilePath(): string {
830830
*
831831
* @throws \Exception
832832
*/
833-
public function verifyIntegrity(string $urlOverride = ''): void {
833+
public function verifyIntegrity(string $urlOverride = '', string $signature = ''): void {
834834
$this->silentLog('[info] verifyIntegrity()');
835835

836836
if ($this->getCurrentReleaseChannel() === 'daily') {
837837
$this->silentLog('[info] current channel is "daily" which is not signed. Skipping verification.');
838838
return;
839839
}
840840

841-
if ($urlOverride !== '') {
842-
$this->silentLog('[info] custom download url provided, cannot verify signature');
843-
return;
844-
}
845-
846-
$response = $this->getUpdateServerResponse();
847-
if (empty($response['signature'])) {
848-
throw new \Exception('No signature specified for defined update');
849-
}
850-
851-
if (!is_string($response['signature'])) {
852-
throw new \Exception('Signature specified for defined update should be a string');
841+
if ($signature === '') {
842+
if ($urlOverride !== '') {
843+
throw new \Exception(
844+
'Custom download url provided. You need to provide a signature with --signature or skip integrity check with --no-verify.'
845+
);
846+
}
847+
$signature = $this->getSignatureFromUpdater();
853848
}
854849

855850
$certificate = <<<EOF
@@ -884,7 +879,7 @@ public function verifyIntegrity(string $urlOverride = ''): void {
884879

885880
$validSignature = openssl_verify(
886881
file_get_contents($this->getDownloadedFilePath()),
887-
base64_decode($response['signature']),
882+
base64_decode($signature),
888883
$certificate,
889884
OPENSSL_ALGO_SHA512
890885
) === 1;
@@ -896,6 +891,19 @@ public function verifyIntegrity(string $urlOverride = ''): void {
896891
$this->silentLog('[info] end of verifyIntegrity()');
897892
}
898893

894+
private function getSignatureFromUpdater(): string {
895+
$response = $this->getUpdateServerResponse();
896+
if (empty($response['signature'])) {
897+
throw new \Exception('No signature specified for defined update');
898+
}
899+
900+
if (!is_string($response['signature'])) {
901+
throw new \Exception('Signature specified for defined update should be a string');
902+
}
903+
904+
return $response['signature'];
905+
}
906+
899907
/**
900908
* Gets the version as declared in $versionFile
901909
*

lib/UpdateCommand.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class UpdateCommand extends Command {
3131
protected bool $skipIntegrityCheck = false;
3232

3333
protected string $urlOverride = '';
34+
protected string $signature = '';
3435

3536
/** Strings of text for stages of updater */
3637
protected array $checkTexts = [
@@ -59,7 +60,8 @@ protected function configure(): void {
5960
->addOption('no-upgrade', null, InputOption::VALUE_NONE, "Don't automatically run occ upgrade")
6061
->addOption('url', null, InputOption::VALUE_OPTIONAL, 'The URL of the Nextcloud release to download')
6162
->addOption('ignore-state', null, InputOption::VALUE_NONE, 'Ignore known state from .step file, do a complete update')
62-
->addOption('no-verify', null, InputOption::VALUE_OPTIONAL, 'Skip integrity verification of the downloaded file')
63+
->addOption('no-verify', null, InputOption::VALUE_NONE, 'Skip integrity verification of the downloaded file')
64+
->addOption('signature', null, InputOption::VALUE_OPTIONAL, 'Base64 signature of the archive (use it in combination with --url option)')
6365
;
6466
}
6567

@@ -78,6 +80,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
7880
$this->skipUpgrade = (bool)$input->getOption('no-upgrade');
7981
$this->skipIntegrityCheck = (bool)$input->getOption('no-verify');
8082
$this->urlOverride = (string)$input->getOption('url');
83+
$this->signature = (string)$input->getOption('signature');
8184
$this->ignoreState = (bool)$input->getOption('ignore-state');
8285

8386
$version = static::getUpdaterVersion();
@@ -463,7 +466,7 @@ protected function executeStep(int $step, OutputInterface $output): array {
463466
$this->updater->silentLog('[info] Skipping integrity check as requested');
464467
break;
465468
}
466-
$this->updater->verifyIntegrity($this->urlOverride);
469+
$this->updater->verifyIntegrity($this->urlOverride, $this->signature);
467470
break;
468471
case 6:
469472
$this->updater->extractDownload();

lib/Updater.php

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -599,11 +599,11 @@ private function getUpdateServerResponse(): array {
599599
*
600600
* @throws \Exception
601601
*/
602-
public function downloadUpdate(string $url = '', ?Closure $downloadProgress = null): void {
602+
public function downloadUpdate(string $urlOverride = '', ?Closure $downloadProgress = null): void {
603603
$this->silentLog('[info] downloadUpdate()');
604604
$this->downloadProgress = $downloadProgress;
605605

606-
$downloadURLs = $url !== '' ? [$url] : $this->getDownloadURLs();
606+
$downloadURLs = $urlOverride !== '' ? [$urlOverride] : $this->getDownloadURLs();
607607

608608
$this->silentLog('[info] will try to download archive from: ' . implode(', ', $downloadURLs));
609609

@@ -625,10 +625,10 @@ public function downloadUpdate(string $url = '', ?Closure $downloadProgress = nu
625625
}
626626
}
627627

628-
foreach ($downloadURLs as $url) {
628+
foreach ($downloadURLs as $urlOverride) {
629629
$this->previousProgress = 0;
630-
$saveLocation = $storageLocation . basename((string)$url);
631-
if ($this->downloadArchive($url, $saveLocation)) {
630+
$saveLocation = $storageLocation . basename((string)$urlOverride);
631+
if ($this->downloadArchive($urlOverride, $saveLocation)) {
632632
return;
633633
}
634634
}
@@ -814,26 +814,21 @@ private function getDownloadedFilePath(): string {
814814
*
815815
* @throws \Exception
816816
*/
817-
public function verifyIntegrity(string $urlOverride = ''): void {
817+
public function verifyIntegrity(string $urlOverride = '', string $signature = ''): void {
818818
$this->silentLog('[info] verifyIntegrity()');
819819

820820
if ($this->getCurrentReleaseChannel() === 'daily') {
821821
$this->silentLog('[info] current channel is "daily" which is not signed. Skipping verification.');
822822
return;
823823
}
824824

825-
if ($urlOverride !== '') {
826-
$this->silentLog('[info] custom download url provided, cannot verify signature');
827-
return;
828-
}
829-
830-
$response = $this->getUpdateServerResponse();
831-
if (empty($response['signature'])) {
832-
throw new \Exception('No signature specified for defined update');
833-
}
834-
835-
if (!is_string($response['signature'])) {
836-
throw new \Exception('Signature specified for defined update should be a string');
825+
if ($signature === '') {
826+
if ($urlOverride !== '') {
827+
throw new \Exception(
828+
'Custom download url provided. You need to provide a signature with --signature or skip integrity check with --no-verify.'
829+
);
830+
}
831+
$signature = $this->getSignatureFromUpdater();
837832
}
838833

839834
$certificate = <<<EOF
@@ -868,7 +863,7 @@ public function verifyIntegrity(string $urlOverride = ''): void {
868863

869864
$validSignature = openssl_verify(
870865
file_get_contents($this->getDownloadedFilePath()),
871-
base64_decode($response['signature']),
866+
base64_decode($signature),
872867
$certificate,
873868
OPENSSL_ALGO_SHA512
874869
) === 1;
@@ -880,6 +875,19 @@ public function verifyIntegrity(string $urlOverride = ''): void {
880875
$this->silentLog('[info] end of verifyIntegrity()');
881876
}
882877

878+
private function getSignatureFromUpdater(): string {
879+
$response = $this->getUpdateServerResponse();
880+
if (empty($response['signature'])) {
881+
throw new \Exception('No signature specified for defined update');
882+
}
883+
884+
if (!is_string($response['signature'])) {
885+
throw new \Exception('Signature specified for defined update should be a string');
886+
}
887+
888+
return $response['signature'];
889+
}
890+
883891
/**
884892
* Gets the version as declared in $versionFile
885893
*

0 commit comments

Comments
 (0)