Skip to content

Commit

Permalink
4.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lbr38 committed May 11, 2024
1 parent 067c229 commit ab5c8e6
Show file tree
Hide file tree
Showing 13 changed files with 374 additions and 120 deletions.
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

0 comments on commit ab5c8e6

Please sign in to comment.