Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.1.0 #165

Merged
merged 1 commit into from
May 13, 2024
Merged

4.1.0 #165

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 21 additions & 28 deletions www/bin/repomanager
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export GPG_TTY=$(tty)
# Main variables
PWD=$(dirname "$0")
WWW_DIR="/var/www/repomanager"
WWW_USER="www-data"
DATA_DIR="/var/lib/repomanager"
REPOS_DIR="/home/repo"
GPGHOME="$DATA_DIR/.gnupg"
Expand Down Expand Up @@ -53,33 +52,25 @@ function permissions

echo -ne "${YELLOW} Setting permissions... ${RESET}"

# Owner on web directory
chmod 750 "$WWW_DIR"
chown -R ${WWW_USER}:repomanager "$WWW_DIR"

# Owner on data directory
chmod 770 "$DATA_DIR"
chown -R ${WWW_USER}:repomanager "$DATA_DIR"

# Owner on repos directory
# Permissions on repos directory
chmod 770 "$REPOS_DIR"
chown -R ${WWW_USER}:repomanager "$REPOS_DIR"
chown -R www-data:repomanager "$REPOS_DIR"
if [ -d "$REPOS_DIR/gpgkeys" ];then
chown www-data:repomanager $REPOS_DIR/gpgkeys/*
chmod 660 $REPOS_DIR/gpgkeys/*
fi

# Permissions on web directory
find "$WWW_DIR" -type d -exec chmod 0770 {} \; &
find "$WWW_DIR" -type f -exec chmod 0660 {} \; &
chmod 750 "$WWW_DIR"
chown -R www-data:repomanager "$WWW_DIR"

# Permissions on data directory
find "$DATA_DIR" -type d -exec chmod 0770 {} \; &
find "$DATA_DIR" -type f -exec chmod 0660 {} \; &

# Permissions on repos directory
find "$REPOS_DIR" -type d -exec chmod 0770 {} \; &
find "$REPOS_DIR" -type f -exec chmod 0660 {} \; &
chmod 770 "$DATA_DIR"
chown -R www-data:repomanager "$DATA_DIR"

# Permissions on .gnupg directory
if [ -d "$GPGHOME" ];then
chown -R ${WWW_USER}:repomanager $GPGHOME
chown -R www-data:repomanager $GPGHOME
chmod 700 $GPGHOME

# Permissions on passphrase
Expand All @@ -88,15 +79,17 @@ function permissions
fi
fi

# Permissions on GPG public key
if [ -d "$REPOS_DIR/gpgkeys" ];then
chown ${WWW_USER}:repomanager $REPOS_DIR/gpgkeys/*
chmod 660 $REPOS_DIR/gpgkeys/*
fi
# Permissions on web directory
find "$WWW_DIR" -type d -exec chmod 0750 {} \; &
find "$WWW_DIR" -type f -exec chmod 0640 {} \; &

if [ -f "$WWW_DIR/bin/repomanager" ];then
chmod 550 $WWW_DIR/bin/repomanager
fi
# Permissions on data directory (except .gnupg directory)
find "$DATA_DIR" ! -path "$GPGHOME" -type d -exec chmod 0770 {} \; &
find "$DATA_DIR" -type f -exec chmod 0660 {} \; &

# Permissions on repos directory
find "$REPOS_DIR" -type d -exec chmod 0770 {} \; &
find "$REPOS_DIR" -type f -exec chmod 0660 {} \; &
}

echo '
Expand Down
32 changes: 24 additions & 8 deletions www/controllers/App/Config/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,6 @@ public static function get()
}
}

if (!defined('RPM_SIGN_IGNORE_MISSING_SIGNATURE')) {
if (!empty($settings['RPM_SIGN_IGNORE_MISSING_SIGNATURE'])) {
define('RPM_SIGN_IGNORE_MISSING_SIGNATURE', $settings['RPM_SIGN_IGNORE_MISSING_SIGNATURE']);
} else {
define('RPM_SIGN_IGNORE_MISSING_SIGNATURE', 'false');
}
}

if (!defined('RELEASEVER')) {
if (!empty($settings['RELEASEVER'])) {
define('RELEASEVER', $settings['RELEASEVER']);
Expand All @@ -188,6 +180,22 @@ public static function get()
}
}

if (!defined('RPM_MISSING_SIGNATURE')) {
if (!empty($settings['RPM_MISSING_SIGNATURE'])) {
define('RPM_MISSING_SIGNATURE', $settings['RPM_MISSING_SIGNATURE']);
} else {
define('RPM_MISSING_SIGNATURE', 'error');
}
}

if (!defined('RPM_INVALID_SIGNATURE')) {
if (!empty($settings['RPM_INVALID_SIGNATURE'])) {
define('RPM_INVALID_SIGNATURE', $settings['RPM_INVALID_SIGNATURE']);
} else {
define('RPM_INVALID_SIGNATURE', 'error');
}
}

// DEB
if (!defined('DEB_REPO')) {
if (!empty($settings['DEB_REPO'])) {
Expand Down Expand Up @@ -221,6 +229,14 @@ public static function get()
}
}

if (!defined('DEB_INVALID_SIGNATURE')) {
if (!empty($settings['DEB_INVALID_SIGNATURE'])) {
define('DEB_INVALID_SIGNATURE', $settings['DEB_INVALID_SIGNATURE']);
} else {
define('DEB_INVALID_SIGNATURE', 'error');
}
}

// GPG signing key
if (!defined('GPG_SIGNING_KEYID')) {
if (!empty($settings['GPG_SIGNING_KEYID'])) {
Expand Down
137 changes: 114 additions & 23 deletions www/controllers/Repo/Mirror/Deb.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Deb extends \Controllers\Repo\Mirror\Mirror
*/
private function getReleaseFile()
{
$this->logOutput(PHP_EOL . 'Getting <code>Release</code> file ... ');
$this->logOutput(PHP_EOL . 'Getting <code>InRelease</code> / <code>Release</code> file ... ');

/**
* Check that Release.xx file exists before downloading it to prevent error message displaying for nothing
Expand All @@ -28,7 +28,7 @@ private function getReleaseFile()
* Print an error and quit if no Release file has been found
*/
if (!file_exists($this->workingDir . '/InRelease') and !file_exists($this->workingDir . '/Release') and !file_exists($this->workingDir . '/Release.gpg')) {
$this->logError('No <code>Release</code> file has been found in the source repository <code>' . $this->url . '/dists/' . $this->dist . '/</code> (looked for <code>InRelease</code>, <code>Release</code> and <code>Release.gpg</code>). Is the URL of the repository correct?', '<code>Release</code> file not found');
$this->logError('No <code>InRelease</code> or <code>Release</code> file has been found in the source repository <code>' . $this->url . '/dists/' . $this->dist . '/</code> (looked for <code>InRelease</code>, <code>Release</code> and <code>Release.gpg</code>). Is the URL of the repository correct?', '<code>Release</code> file not found');
}

$this->logOK();
Expand All @@ -42,11 +42,10 @@ private function getReleaseFile()
*/
private function parseReleaseFile()
{
if (file_exists($this->workingDir . '/InRelease')) {
$content = file($this->workingDir . '/InRelease');
} elseif (file_exists($this->workingDir . '/Release')) {
$content = file($this->workingDir . '/Release');
}
/**
* Get valid InRelease / Release file content
*/
$content = file($this->workingDir . '/' . $this->validReleaseFile);

/**
* Process research of Packages indices for each arch
Expand Down Expand Up @@ -122,10 +121,10 @@ private function parseReleaseFile()
* If no Packages.xx/Sources.xx file has been found for this arch, throw an error
*/
if ($arch == 'src') {
$this->logError('No ' . $arch . ' <code>Sources</code> indices file has been found in the <code>Release</code> file.', 'Cannot retrieve <code>' . $arch . '</code> <code>Packages</code> indices file');
$this->logError('No ' . $arch . ' <code>Sources</code> indices file has been found in the <code>' . $this->validReleaseFile . '</code> file.', 'Cannot retrieve <code>' . $arch . '</code> <code>Packages</code> indices file');
}
if ($arch != 'src') {
$this->logError('No ' . $arch . ' <code>Packages</code> indices file has been found in the <code>Release</code> file.', 'Cannot retrieve <code>' . $arch . '</code> <code>Packages</code> indices file');
$this->logError('No ' . $arch . ' <code>Packages</code> indices file has been found in the <code>' . $this->validReleaseFile . '</code> file.', 'Cannot retrieve <code>' . $arch . '</code> <code>Packages</code> indices file');
}
}

Expand Down Expand Up @@ -445,52 +444,144 @@ private function parseSourcesIndiceFile()
private function checkReleaseGPGSignature()
{
/**
* Quit if signature check is disabled
* List of possible Release files to check
*/
$releaseFiles = array(
array(
'name' => 'InRelease',
'signature' => ''
),

array(
'name' => 'Release',
'signature' => 'Release.gpg'
)
);

/**
* If signature check is disabled, then just set a valid Release file
*/
if ($this->checkSignature == 'false') {
foreach ($releaseFiles as $releaseFile) {
if (!file_exists($this->workingDir . '/' . $releaseFile['name'])) {
continue;
}

$this->validReleaseFile = $releaseFile['name'];
}

/**
* If no valid Release file has been found, throw an error
*/
if (empty($this->validReleaseFile)) {
$this->logError('No valid <code>InRelease</code> or <code>Release</code> file found. Please ensure that the remote repository is correctly built.', 'Release file check fail');
}

return;
}

$this->logOutput(PHP_EOL . 'Checking <code>Release</code> GPG signature ... ');

/**
* Check signature from InRelease file in priority, else from Release.gpg file
* If signature check is enabled, then look for a valid Release file
*/
if (file_exists($this->workingDir . '/InRelease')) {
$this->checkGPGSignature($this->workingDir . '/InRelease');
} elseif (file_exists($this->workingDir . '/Release.gpg')) {
$this->checkGPGSignature($this->workingDir . '/Release.gpg', $this->workingDir . '/Release');
foreach ($releaseFiles as $releaseFile) {
if (!file_exists($this->workingDir . '/' . $releaseFile['name'])) {
continue;
}

$this->logOutput(PHP_EOL . 'Checking <code>' . $releaseFile['name'] . '</code> GPG signature ... ');

/**
* Check that GPG signature is valid (signed with a known key)
*/
try {
if (!empty($releaseFile['signature'])) {
$this->checkGPGSignature($this->workingDir . '/' . $releaseFile['signature'], $this->workingDir . '/' . $releaseFile['name']);
} else {
$this->checkGPGSignature($this->workingDir . '/' . $releaseFile['name']);
}

/**
* If file's signature is valid, then set file as the valid Release file and quit the loop
*/
$this->validReleaseFile = $releaseFile['name'];

$this->logOK();

break;
} catch (Exception $e) {
if (DEB_INVALID_SIGNATURE == 'error') {
$this->logError($e->getMessage(), 'GPG signature check failed');
}

if (DEB_INVALID_SIGNATURE == 'ignore') {
$this->logWarning($e->getMessage());
continue;
}
}
}

$this->logOK();
/**
* If no valid Release file has been found, throw an error
*/
if (empty($this->validReleaseFile)) {
$this->logError(PHP_EOL . 'No <code>InRelease</code> or <code>Release</code> file found with a valid GPG signature. Please check that you have imported the GPG key used to sign the repository.', 'GPG signature check failed');
}
}

/**
* Check GPG signature of specified file
*/
private function checkGPGSignature(string $signatureFile, string $clearFile = null)
private function checkGPGSignature(string $signedFile, string $clearFile = null)
{
/**
* Check that signature file exists
*/
if (!file_exists($signedFile)) {
throw new Exception('No ' . end(explode('/', $signedFile)) . ' signed file found. Are you sure that the remote repository is signed?');
}

/**
* If a clear file has been specified, check that it exists
*/
if (!empty($clearFile) and !file_exists($clearFile)) {
throw new Exception('No ' . end(explode('/', $clearFile)) . ' clear file found. Are you sure that the remote repository is signed?');
}

/**
* If a clear file exists (e.g. Release) then specify it as second argument, as suggested by gpgv:
* Please remember that the signature file (.sig or .asc)
* should be the first file given on the command line.
* e.g. gpgv --homedir /var/lib/repomanager/.gnupg/ Release.gpg Release
*/
if (!empty($clearFile)) {
$myprocess = new \Controllers\Process('/usr/bin/gpgv --homedir ' . GPGHOME . ' ' . $signatureFile . ' ' . $clearFile);
$myprocess = new \Controllers\Process('/usr/bin/gpgv --homedir ' . GPGHOME . ' ' . $signedFile . ' ' . $clearFile);
} else {
$myprocess = new \Controllers\Process('/usr/bin/gpgv --homedir ' . GPGHOME . ' ' . $signatureFile);
$myprocess = new \Controllers\Process('/usr/bin/gpgv --homedir ' . GPGHOME . ' ' . $signedFile);
}

$myprocess->execute();
$output = $myprocess->getOutput();
$myprocess->close();

/**
* If gpgv returned an error then signature is invalid
* If 'Can't check signature: No public key' is found in the output, then the GPG key is not imported
*/
if (preg_match("/Can't check signature: No public key/", $output)) {
throw new Exception('No GPG key could verify the signature of <code>' . end(explode('/', $signedFile)) . '</code> file. Please check that you have imported the GPG key used to sign the repository.');
}

/**
* If 'BAD signature from' is found in the output, then the signature is invalid / broken
*/
if (preg_match("/BAD signature from/", $output)) {
throw new Exception('Invalid signature of <code>' . end(explode('/', $signedFile)) . '</code> file: ' . PHP_EOL . '<pre class="codeblock">' . $output . '</pre>');
}

/**
* Else if the exit code is not 0, then print the error message
*/
if ($myprocess->getExitCode() != 0) {
$this->logError('No GPG key could verify the signature of downloaded file <code>' . $signatureFile . '</code>: ' . PHP_EOL . $output, 'GPG signature check fail');
throw new Exception('Invalid signature or no GPG key could verify the signature of <code>' . end(explode('/', $signedFile)) . '</code> file: ' . PHP_EOL . '<pre class="codeblock">' . $output . '</pre>');
}
}

Expand Down
Loading
Loading