Merge pull request #1787 from RaspAP/maint/plugin-installer-keys

Updates PluginInstaller to handle signed third-party packages
This commit is contained in:
Bill Zimmerman
2025-03-20 08:11:08 +01:00
committed by GitHub
4 changed files with 87 additions and 13 deletions

View File

@@ -23,6 +23,7 @@ class PluginInstaller
private $rootPath;
private $pluginsManifest;
private $repoPublic;
private $helperScriptPath;
public function __construct()
{
@@ -34,6 +35,7 @@ class PluginInstaller
$this->rootPath = $_SERVER['DOCUMENT_ROOT'];
$this->pluginsManifest = '/plugins/manifest.json';
$this->repoPublic = $this->getRepository();
$this->helperScriptPath = RASPI_CONFIG.'/plugins/plugin_helper.sh';
}
// Returns a single instance of PluginInstaller
@@ -187,6 +189,10 @@ class PluginInstaller
$this->addSudoers($manifest['sudoers']);
$rollbackStack[] = 'removeSudoers';
}
if (!empty($manifest['keys'])) {
$this->installRepositoryKeys($manifest['keys']);
$rollbackStack[] = 'uninstallRepositoryKeys';
}
if (!empty($manifest['dependencies'])) {
$this->installDependencies($manifest['dependencies']);
$rollbackStack[] = 'uninstallDependencies';
@@ -207,7 +213,6 @@ class PluginInstaller
$this->copyPluginFiles($pluginDir, $this->rootPath);
$rollbackStack[] = 'removePluginFiles';
}
return true;
} catch (\Exception $e) {
throw new \Exception('Installation step failed: ' . $e->getMessage());
@@ -243,7 +248,7 @@ class PluginInstaller
$cmd = sprintf('sudo visudo -cf %s', escapeshellarg($tmpSudoers));
$return = shell_exec($cmd);
if (strpos(strtolower($return), 'parsed ok') !== false) {
$cmd = sprintf('sudo /etc/raspap/plugins/plugin_helper.sh sudoers %s', escapeshellarg($tmpSudoers));
$cmd = sprintf('sudo %s sudoers %s', escapeshellarg($this->helperScriptPath), escapeshellarg($tmpSudoers));
$return = shell_exec($cmd);
if (strpos(strtolower($return), 'ok') === false) {
throw new \Exception('Plugin helper failed to install sudoers.');
@@ -263,7 +268,7 @@ class PluginInstaller
$packages = array_keys($dependencies);
$packageList = implode(' ', $packages);
$cmd = sprintf('sudo /etc/raspap/plugins/plugin_helper.sh packages %s', escapeshellarg($packageList));
$cmd = sprintf('sudo %s packages %s', escapeshellarg($this->helperScriptPath), escapeshellarg($packageList));
$return = shell_exec($cmd);
if (strpos(strtolower($return), 'ok') === false) {
throw new \Exception('Plugin helper failed to install depedencies.');
@@ -283,7 +288,7 @@ class PluginInstaller
$username = escapeshellarg($user['name']);
$password = escapeshellarg($user['pass']);
$cmd = sprintf('sudo /etc/raspap/plugins/plugin_helper.sh user %s %s', $username, $password);
$cmd = sprintf('sudo %s user %s %s', escapeshellarg($this->helperScriptPath), $username, $password);
$return = shell_exec($cmd);
if (strpos(strtolower($return), 'ok') === false) {
throw new \Exception('Plugin helper failed to create user: ' . $user['name']);
@@ -306,7 +311,7 @@ class PluginInstaller
$destination = $this->rootPath . '/' . ltrim($destination, '/');
}
$destination = escapeshellarg($destination);
$cmd = sprintf('sudo /etc/raspap/plugins/plugin_helper.sh config %s %s', $source, $destination);
$cmd = sprintf('sudo %s config %s %s', escapeshellarg($this->helperScriptPath), $source, $destination);
$return = shell_exec($cmd);
if (strpos(strtolower($return), 'ok') === false) {
throw new \Exception("Failed to copy configuration file: $source to $destination");
@@ -325,7 +330,7 @@ class PluginInstaller
foreach ($javascript as $js) {
$source = escapeshellarg($pluginDir . DIRECTORY_SEPARATOR . $js);
$destination = escapeshellarg($this->rootPath . DIRECTORY_SEPARATOR . 'app/js/plugins/');
$cmd = sprintf('sudo /etc/raspap/plugins/plugin_helper.sh javascript %s %s', $source, $destination);
$cmd = sprintf('sudo %s javascript %s %s', escapeshellarg($this->helperScriptPath), $source, $destination);
$return = shell_exec($cmd);
if (strpos(strtolower($return), 'ok') === false) {
throw new \Exception("Failed to copy JavaScript file: $source");
@@ -343,13 +348,43 @@ class PluginInstaller
{
$source = escapeshellarg($source);
$destination = escapeshellarg($destination . DIRECTORY_SEPARATOR .$this->pluginPath . DIRECTORY_SEPARATOR . $this->pluginName);
$cmd = sprintf('sudo /etc/raspap/plugins/plugin_helper.sh plugin %s %s', $source, $destination);
$cmd = sprintf('sudo %s plugin %s %s', escapeshellarg($this->helperScriptPath), $source, $destination);
$return = shell_exec($cmd);
if (strpos(strtolower($return), 'ok') === false) {
throw new \Exception('Failed to copy plugin files to: ' . $destination);
}
}
/**
* Installs repository keys for third-party apt packages
*
* @param array $keys Array containing key_url, keyring, repo, and sources
* @throws Exception on key installation failure
*/
public function installRepositoryKeys(array $keys): void
{
if (!is_array($keys)) {
throw new \Exception("Invalid repository key structure: array expected");
}
foreach ($keys as $keyData) {
if (!isset($keyData['key_url'], $keyData['keyring'], $keyData['repo'], $keyData['sources'])) {
throw new \Exception("Invalid repository key structure: " . json_encode($keyData));
}
$cmd = sprintf(
'sudo %s keys %s %s %s %s',
escapeshellarg($this->helperScriptPath),
escapeshellarg($keyData['key_url']),
escapeshellarg($keyData['keyring']),
escapeshellarg($keyData['repo']),
escapeshellarg($keyData['sources'])
);
$return = shell_exec($cmd);
if (strpos(strtolower($return), 'ok') === false) {
throw new \Exception("Failed to add repository and key");
}
}
}
/**
* Parses and returns a downloaded plugin manifest
*