diff --git a/docker/Dockerfile b/docker/Dockerfile
index a26a6ebc..92c7c1d6 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -19,7 +19,7 @@ ARG max_upload_size
# Install dependencies
RUN apt-get update -y
-RUN apt-get install findutils iputils-ping git gnupg2 rpm librpmsign9 createrepo-c apt-utils curl ca-certificates apt-transport-https dnsutils xz-utils bzip2 vim -y
+RUN apt-get install findutils iputils-ping git gnupg2 rpm librpmsign9 createrepo-c apt-utils curl ca-certificates apt-transport-https dnsutils xz-utils bzip2 zstd vim -y
# Install postfix
RUN apt-get install postfix -y
diff --git a/www/controllers/Common.php b/www/controllers/Common.php
index 90b94b61..128a41c0 100644
--- a/www/controllers/Common.php
+++ b/www/controllers/Common.php
@@ -535,6 +535,23 @@ public static function xzUncompress(string $filename, string $outputFilename = n
unset($myprocess, $content);
}
+ /**
+ * Uncompress specified zstd file 'file.zst' to 'file'
+ */
+ public static function zstdUncompress(string $filename)
+ {
+ $myprocess = new \Controllers\Process('/usr/bin/unzstd ' . $filename);
+ $myprocess->execute();
+ $content = $myprocess->getOutput();
+ $myprocess->close();
+
+ if ($myprocess->getExitCode() != 0) {
+ throw new Exception('Error while uncompressing zstd file ' . $filename . ': ' . $content);
+ }
+
+ unset($myprocess, $content);
+ }
+
/**
* Return true if distant URL is reachable
* The target URL can be a file or a directory
diff --git a/www/controllers/Gpg.php b/www/controllers/Gpg.php
index 18e447db..834315ff 100644
--- a/www/controllers/Gpg.php
+++ b/www/controllers/Gpg.php
@@ -306,6 +306,13 @@ public function import(string $gpgKeyUrl, string $gpgKeyFingerprint, string $gpg
throw new Exception('Invalid URL');
}
+ /**
+ * If the user specified a URL in the fingerprint field, quit
+ */
+ if (!empty($gpgKeyFingerprint) and preg_match('#^http(s)?://#', $gpgKeyFingerprint)) {
+ throw new Exception('Invalid fingerprint');
+ }
+
try {
/**
* Import GPG key from URL
@@ -339,76 +346,88 @@ public function import(string $gpgKeyUrl, string $gpgKeyFingerprint, string $gpg
}
/**
- * Import a plain text GPG key
+ * Import a file-based GPG key
*/
- public function importPlainText(string $gpgKey)
+ private function importRawContent(string $fileContent) : array
{
- $gpgKey = \Controllers\Common::validateData($gpgKey);
- $gpgTempFile = TEMP_DIR . '/.repomanager-newgpgkey.tmp';
-
- /**
- * Check if the ASCII text contains invalid characters
- */
- if (!\Controllers\Common::isAlphanum($gpgKey, array('-', '=', '+', '/', ' ', ':', '.', '(', ')', "\n", "\r"))) {
- throw new Exception('ASCII GPG key contains invalid characters');
- }
-
/**
* Quit if user tries to import a GPG from url
*/
- if (preg_match('#http(s)?://#', $gpgKey)) {
+ if (preg_match('#http(s)?://#', $fileContent)) {
throw new Exception('GPG key must be specified in ASCII text format');
}
/**
* Quit if the user tries to import a file on the system
*/
- if (file_exists($gpgKey)) {
+ if (file_exists($fileContent)) {
throw new Exception('GPG key must be specified in ASCII text format');
}
/**
* Create a temporary file with the ASCII text
*/
- if (!file_put_contents($gpgTempFile, $gpgKey)) {
+ $gpgTempFile = TEMP_DIR . '/.repomanager-newgpgkey.tmp';
+ if (!file_put_contents($gpgTempFile, $fileContent)) {
throw new Exception('could not initialize GPG import');
}
- /**
- * First, extract the fingerprints from the GPG key (there could be one or multiple)
- */
- $myprocess = new Process("/usr/bin/gpg --homedir " . GPGHOME . " --no-default-keyring --keyring " . GPGHOME . "/trustedkeys.gpg --show-keys --with-fingerprint --with-colons " . $gpgTempFile . " | grep '^fpr' | cut -d: -f10");
- $myprocess->execute();
- $content = $myprocess->getOutput();
- $myprocess->close();
+ try {
+ /**
+ * First, extract the fingerprints from the GPG key (there could be one or multiple)
+ */
+ $myprocess = new Process("/usr/bin/gpg --homedir " . GPGHOME . " --no-default-keyring --keyring " . GPGHOME . "/trustedkeys.gpg --show-keys --with-fingerprint --with-colons " . $gpgTempFile . " | grep '^fpr' | cut -d: -f10");
+ $myprocess->execute();
+ $content = $myprocess->getOutput();
+ $myprocess->close();
- if ($myprocess->getExitCode() != 0) {
- throw new Exception('could not retrieve fingerprint(s) from GPG key:
"' . $content . ''); - } + if ($myprocess->getExitCode() != 0) { + throw new Exception('could not retrieve fingerprint(s) from GPG key:
"' . $content . ''); + } - /** - * Output will print all fingerprints on multiple lines (one per fingerprint) - */ - $fingerprints = explode(PHP_EOL, $content); + /** + * Output will print all fingerprints on multiple lines (one per fingerprint) + */ + $fingerprints = explode(PHP_EOL, $content); - /** - * Import file into the repomanager trusted keyring - */ - $myprocess = new \Controllers\Process('/usr/bin/gpg --no-default-keyring --keyring ' . GPGHOME . '/trustedkeys.gpg --import ' . $gpgTempFile); - $myprocess->execute(); - $content = $myprocess->getOutput(); - $myprocess->close(); + /** + * Import file into the repomanager trusted keyring + */ + $myprocess = new \Controllers\Process('/usr/bin/gpg --no-default-keyring --keyring ' . GPGHOME . '/trustedkeys.gpg --import ' . $gpgTempFile); + $myprocess->execute(); + $content = $myprocess->getOutput(); + $myprocess->close(); + + if ($myprocess->getExitCode() != 0) { + throw new Exception('
' . $content . ''); + } + + return $fingerprints; + } finally { + /** + * Delete temp file + */ + if (!unlink($gpgTempFile)) { + throw new Exception('cannot delete temporary file: ' . $tempFile); + } + } + } + + /** + * Import a plain text GPG key + */ + public function importPlainText(string $gpgKey) : array + { + $gpgKey = \Controllers\Common::validateData($gpgKey); /** - * Delete temp file + * Check if the ASCII text contains invalid characters */ - unlink($gpgTempFile); - - if ($myprocess->getExitCode() != 0) { - throw new Exception('
' . $content . ''); + if (!\Controllers\Common::isAlphanum($gpgKey, array('-', '=', '+', '/', ' ', ':', '.', '(', ')', "\n", "\r"))) { + throw new Exception('ASCII GPG key contains invalid characters'); } - return $fingerprints; + return $this->importRawContent($gpgKey); } /** @@ -417,9 +436,6 @@ public function importPlainText(string $gpgKey) */ public function importFromUrl(string $url) : array { - $fingerprints = []; - $tempFile = TEMP_DIR . '/import-gpgkey.asc'; - /** * Quit if the URL is not valid */ @@ -436,16 +452,15 @@ public function importFromUrl(string $url) : array * Init curl */ $ch = curl_init(); - $targetFile = fopen($tempFile, 'w'); /** * Download GPG key from URL */ curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_FILE, $targetFile); // set output file curl_setopt($ch, CURLOPT_TIMEOUT, 5); // set timeout curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // follow redirect curl_setopt($ch, CURLOPT_ENCODING, ''); // use compression if any + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // output content to return /** * If a proxy has been specified @@ -454,66 +469,46 @@ public function importFromUrl(string $url) : array curl_setopt($ch, CURLOPT_PROXY, PROXY); } - if (curl_exec($ch) === false) { - /** - * If curl has failed (meaning a curl param might be invalid) - */ - throw new Exception('curl error: ' . curl_error($ch)); + $result = curl_exec($ch); - curl_close($ch); - fclose($targetFile); - } + try { + if ($result === false) { + /** + * If curl has failed (meaning a curl param might be invalid) + */ + throw new Exception('curl error: ' . curl_error($ch)); + } - /** - * Check that the http return code is 200 (the file has been downloaded) - */ - $status = curl_getinfo($ch); + if (empty($result)) { + /** + * If key is empty, meaning bad key + */ + throw new Exception('empty gpg key response (downloaded file is empty)'); + } - if ($status["http_code"] != 200) { /** - * If return code is 404 + * Check that the http return code is 200 (the file has been downloaded) */ - if ($status["http_code"] == '404') { - throw new Exception('404 file not found'); - } else { - throw new Exception('file could not be downloaded (http return code is: ' . $status["http_code"] . ')'); + $status = curl_getinfo($ch); + + if ($status["http_code"] != 200) { + /** + * If return code is 404 + */ + if ($status["http_code"] == '404') { + throw new Exception('404 file not found'); + } else { + throw new Exception('file could not be downloaded (http return code is: ' . $status["http_code"] . ')'); + } } - + } finally { curl_close($ch); - fclose($targetFile); - - return false; - } - - fclose($targetFile); - curl_close($ch); - - /** - * Get GPG key content - */ - $gpgKey = file_get_contents($tempFile); - - if ($gpgKey === false) { - throw new Exception('error while reading temporary file: ' . $tempFile); - } - - if (empty($gpgKey)) { - throw new Exception('empty while reading temporary file: ' . $tempFile . ' (file is empty)'); } /** * Import GPG key */ - $fingerprints = $this->importPlainText($gpgKey); - - /** - * Delete temp file - */ - if (!unlink($tempFile)) { - throw new Exception('cannot delete temporary file: ' . $tempFile); - } - - return $fingerprints; + return $this->importRawContent($result); } /** diff --git a/www/controllers/Repo/Mirror/Deb.php b/www/controllers/Repo/Mirror/Deb.php index e305e557..7be8716c 100644 --- a/www/controllers/Repo/Mirror/Deb.php +++ b/www/controllers/Repo/Mirror/Deb.php @@ -99,7 +99,7 @@ private function parseReleaseFile() $splittedLine = explode(' ', trim($line)); /** - * We only need the location with its SHA256 (64 caracters long) + * We only need the location with its SHA256 (64 characters long) * e.g: bd29d2ec28c10fec66a139d8e9a88ca01ff0f2533ca3fab8dc33c13b533059c1 1279885 main/binary-amd64/Packages */ if (strlen($splittedLine[0]) == '64') { @@ -181,7 +181,7 @@ private function parseReleaseFile() $splittedLine = explode(' ', trim($line)); /** - * We only need the location with its md5sum (32 caracters long) + * We only need the location with its md5sum (32 characters long) * e.g: 35e89f49cdfaa179e552aee1d67c5cdb 2478327 main/i18n/Translation-fr.bz2 */ if (strlen($splittedLine[0]) == '32') { diff --git a/www/controllers/Repo/Mirror/Rpm.php b/www/controllers/Repo/Mirror/Rpm.php index 857a6c7c..9af0828b 100644 --- a/www/controllers/Repo/Mirror/Rpm.php +++ b/www/controllers/Repo/Mirror/Rpm.php @@ -451,6 +451,11 @@ private function parsePrimaryPackagesList(string $primaryFile) */ } elseif ($mime == 'application/gzip') { \Controllers\Common::gunzip($primaryFile); + /** + * Case mime type is application/zstd (.gz file) + */ + } elseif ($mime == 'application/zstd') { + \Controllers\Common::zstdUncompress($primaryFile); /** * Case it's another mime type, throw an error */ @@ -458,7 +463,7 @@ private function parsePrimaryPackagesList(string $primaryFile) throw new Exception('MIME type not supported: ' . $mime . '. Please contact the developer to add support for this MIME type.'); } } catch (Exception $e) { - throw new Exception($e, 'Error while uncompressing
'. end(explode('/', $primaryFile)) . '
');
+ throw new Exception('Error while uncompressing '. end(explode('/', $primaryFile)) . '
: ' . $e->getMessage() . ''); } /** diff --git a/www/controllers/Repo/Source/Deb.php b/www/controllers/Repo/Source/Deb.php index 4a4d1470..40e12fd0 100644 --- a/www/controllers/Repo/Source/Deb.php +++ b/www/controllers/Repo/Source/Deb.php @@ -240,12 +240,15 @@ public function addGpgKey(int $id, int $distributionId, string $gpgKeyUrl, strin */ foreach ($fingerprints as $fingerprint) { // Ignore fingerprint if already exists - foreach ($currentParams['distributions'][$distributionId]['gpgkeys'] as $gpgKeyDefinition) { - if (isset($gpgKeyDefinition['fingerprint']) and $gpgKeyDefinition['fingerprint'] == $fingerprint) { - continue 2; + if (!empty($currentParams['distributions'][$distributionId]['gpgkeys'])) { + foreach ($currentParams['distributions'][$distributionId]['gpgkeys'] as $gpgKeyDefinition) { + if (isset($gpgKeyDefinition['fingerprint']) and $gpgKeyDefinition['fingerprint'] == $fingerprint) { + continue 2; + } } } + // Otherwise add the fingerprint $currentParams['distributions'][$distributionId]['gpgkeys'][] = array( 'fingerprint' => $fingerprint ); diff --git a/www/controllers/Repo/Source/Rpm.php b/www/controllers/Repo/Source/Rpm.php index 0314ad37..743dbcc7 100644 --- a/www/controllers/Repo/Source/Rpm.php +++ b/www/controllers/Repo/Source/Rpm.php @@ -28,9 +28,11 @@ public function addReleasever(int $id, string $name) /** * Check that a release version with the same name does not already exist */ - foreach ($currentParams['releasever'] as $releasever) { - if ($releasever['name'] == $name) { - throw new Exception('Release version ' . $name . ' already exists'); + if (!empty($currentParams['releasever'])) { + foreach ($currentParams['releasever'] as $releasever) { + if ($releasever['name'] == $name) { + throw new Exception('Release version ' . $name . ' already exists'); + } } } @@ -156,12 +158,15 @@ public function addGpgKey(int $id, int $releaseverId, string $gpgKeyUrl, string */ foreach ($fingerprints as $fingerprint) { // Ignore fingerprint if already exists - foreach ($currentParams['releasever'][$releaseverId]['gpgkeys'] as $gpgKeyDefinition) { - if (isset($gpgKeyDefinition['fingerprint']) and $gpgKeyDefinition['fingerprint'] == $fingerprint) { - continue 2; + if (!empty($currentParams['releasever'][$releaseverId]['gpgkeys'])) { + foreach ($currentParams['releasever'][$releaseverId]['gpgkeys'] as $gpgKeyDefinition) { + if (isset($gpgKeyDefinition['fingerprint']) and $gpgKeyDefinition['fingerprint'] == $fingerprint) { + continue 2; + } } } + // Otherwise add the fingerprint $currentParams['releasever'][$releaseverId]['gpgkeys'][] = array( 'fingerprint' => $fingerprint ); diff --git a/www/public/resources/styles/common.css b/www/public/resources/styles/common.css index 2dbb7666..75795dc0 100644 --- a/www/public/resources/styles/common.css +++ b/www/public/resources/styles/common.css @@ -213,6 +213,7 @@ pre.codeblock { .min-height-100 {min-height: 100px}.min-height-200 {min-height: 200px}.min-height-300 {min-height: 300px}.min-height-400 {min-height: 400px}.min-height-500 {min-height: 500px}.min-height-600 {min-height: 600px}.min-height-700 {min-height: 700px}.min-height-800 {min-height: 800px}.min-height-900 {min-height: 900px}.min-height-1000 {min-height: 1000px} .min-width-100 {min-width: 100px}.min-width-200 {min-width: 200px}.min-width-300 {min-width: 300px}.min-width-400 {min-width: 400px}.min-width-500 {min-width: 500px}.min-width-600 {min-width: 600px}.min-width-700 {min-width: 700px}.min-width-800 {min-width: 800px}.min-width-900 {min-width: 900px}.min-width-1000 {min-width: 1000px} .width-100{width:100%} +.height-100{height:100%} .max-width-fit{max-width:fit-content} .resize-disabled{resize:none;} @@ -344,6 +345,10 @@ td { /** * Forms, button, input, textarea */ +input { + accent-color: #15bf7f; +} + input[type=text], input[type=date], input[type=time], input[type=number], input[type=email], input[type=password], input[type=color], input[type=file], select { width: 100%; height: 35px; diff --git a/www/templates/source-repositories/deb/proxmox-ve.yml b/www/templates/source-repositories/deb/proxmox-ve.yml new file mode 100644 index 00000000..2c0efd42 --- /dev/null +++ b/www/templates/source-repositories/deb/proxmox-ve.yml @@ -0,0 +1,111 @@ +--- +description: Proxmox Virtual Environment +type: deb +repositories: + - name: pve-public + type: deb + description: Proxmox Virtual Environment Public Repositories + url: http://download.proxmox.com/debian/pve + distributions: + - name: bookworm + description: PVE 8 for Debian Bookworm + components: + - name: pve-no-subscription + - name: pvetest + gpgkeys: + - fingerprint: F4E136C67CDCE41AE6DE6FC81140AF8F639E0C39 + - link: https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg + - name: bullseye + description: PVE 7 for Debian Bullseye + components: + - name: pve-no-subscription + - name: pvetest + gpgkeys: + - fingerprint: 28139A2F830BD68478A1A01FDD4BA3917E23BF59 + - link: https://enterprise.proxmox.com/debian/proxmox-release-bullseye.gpg + - name: buster + description: PVE 6 for Debian Buster + components: + - name: pve-no-subscription + - name: pvetest + gpgkeys: + - fingerprint: 353479F83781D7F8ED5F5AC57BF2812E8A6E88E0 + - link: https://enterprise.proxmox.com/debian/proxmox-ve-release-6.x.gpg + - name: stretch + description: PVE 5 for Debian Stretch + components: + - name: pve-no-subscription + - name: pvetest + gpgkeys: + - fingerprint: 359E95965E2C3D643159CD300D9A1950E2EF0603 + - link: https://enterprise.proxmox.com/debian/proxmox-ve-release-5.x.gpg + - name: stretch + description: PVE 4 for Debian Jessie + components: + - name: pve-no-subscription + - name: pvetest + gpgkeys: + - fingerprint: BE257BAA5D406D01157D323EC23AC7F49887F95A + - link: https://enterprise.proxmox.com/debian/proxmox-ve-release-4.x.gpg + - name: stretch + description: PVE 3 for Debian Wheezy + components: + - name: pve-no-subscription + - name: pvetest + gpgkeys: + - fingerprint: BE257BAA5D406D01157D323EC23AC7F49887F95A + - link: https://enterprise.proxmox.com/debian/key.asc + - name: squeeze + description: PVE 2 for Debian Squeeze + components: + - name: pve + gpgkeys: + - fingerprint: BE257BAA5D406D01157D323EC23AC7F49887F95A + - link: https://enterprise.proxmox.com/debian/key.asc + - name: pve-enterprise + type: deb + description: Proxmox Virtual Environment Enterprise Repositories + url: https://enterprise.proxmox.com/debian/pve + distributions: + - name: bookworm + description: PVE 8 for Debian Bookworm + components: + - name: pve-enterprise + gpgkeys: + - fingerprint: F4E136C67CDCE41AE6DE6FC81140AF8F639E0C39 + - link: https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg + - name: bullseye + description: PVE 7 for Debian Bullseye + components: + - name: pve-enterprise + gpgkeys: + - fingerprint: 28139A2F830BD68478A1A01FDD4BA3917E23BF59 + - link: https://enterprise.proxmox.com/debian/proxmox-release-bullseye.gpg + - name: buster + description: PVE 6 for Debian Buster + components: + - name: pve-enterprise + gpgkeys: + - fingerprint: 353479F83781D7F8ED5F5AC57BF2812E8A6E88E0 + - link: https://enterprise.proxmox.com/debian/proxmox-ve-release-6.x.gpg + - name: stretch + description: PVE 5 for Debian Stretch + components: + - name: pve-enterprise + gpgkeys: + - fingerprint: 359E95965E2C3D643159CD300D9A1950E2EF0603 + - link: https://enterprise.proxmox.com/debian/proxmox-ve-release-5.x.gpg + - name: stretch + description: PVE 4 for Debian Jessie + components: + - name: pve-enterprise + gpgkeys: + - fingerprint: BE257BAA5D406D01157D323EC23AC7F49887F95A + - link: https://enterprise.proxmox.com/debian/proxmox-ve-release-4.x.gpg + - name: stretch + description: PVE 3 for Debian Wheezy + components: + - name: pve-enterprise + gpgkeys: + - fingerprint: BE257BAA5D406D01157D323EC23AC7F49887F95A + - link: https://enterprise.proxmox.com/debian/key.asc diff --git a/www/update/database/4.12.1.php b/www/update/database/4.12.1.php index 212e9358..798b50cb 100644 --- a/www/update/database/4.12.1.php +++ b/www/update/database/4.12.1.php @@ -21,6 +21,7 @@ $lists = [ // deb 'github/deb/debian', + 'github/deb/debian', // TODO temporary fix: import the same source twice to avoid a bug with gpg initialization, to fix 'github/deb/debian-archive', 'github/deb/ubuntu', 'github/deb/ubuntu-archive', diff --git a/www/version b/www/version index 99463916..418b826b 100644 --- a/www/version +++ b/www/version @@ -1 +1 @@ -4.16.1 \ No newline at end of file +4.16.2 \ No newline at end of file