mirror of
https://github.com/billz/raspap-webgui.git
synced 2025-12-26 23:26:47 +01:00
Merge pull request #1787 from RaspAP/maint/plugin-installer-keys
Updates PluginInstaller to handle signed third-party packages
This commit is contained in:
@@ -496,6 +496,7 @@ $('#install-user-plugin').on('shown.bs.modal', function (e) {
|
||||
$('#plugin-license').text(manifestData.license || 'Unknown');
|
||||
$('#plugin-locale').text(manifestData.default_locale || 'Unknown');
|
||||
$('#plugin-configuration').html(formatProperty(manifestData.configuration || 'None'));
|
||||
$('#plugin-packages').html(formatProperty(manifestData.keys || 'None'));
|
||||
$('#plugin-dependencies').html(formatProperty(manifestData.dependencies || 'None'));
|
||||
$('#plugin-javascript').html(formatProperty(manifestData.javascript || 'None'));
|
||||
$('#plugin-sudoers').html(formatProperty(manifestData.sudoers || 'None'));
|
||||
|
||||
@@ -123,16 +123,50 @@ case "$action" in
|
||||
echo "OK"
|
||||
;;
|
||||
|
||||
"keys")
|
||||
[ $# -ne 4 ] && { echo "Usage: $0 keys <key_url> <keyring> <repo> <sources>"; exit 1; }
|
||||
|
||||
key_url="$1"
|
||||
keyring="$2"
|
||||
repo="$3"
|
||||
list_file="$4"
|
||||
|
||||
# add repository GPG key if it doesn't already exist
|
||||
if [ ! -f "$keyring" ]; then
|
||||
echo "Downloading GPG key from $key_url..."
|
||||
curl -fsSL "$key_url" | sudo tee "$keyring" > /dev/null || { echo "Error: Failed to download GPG key."; exit 1; }
|
||||
else
|
||||
echo "Repository GPG key already exists at $keyring"
|
||||
fi
|
||||
|
||||
# add repository list if not present
|
||||
if [ ! -f "$list_file" ]; then
|
||||
echo "Adding repository $repo to sources list"
|
||||
curl -fsSL "$repo" | sudo tee "$list_file" > /dev/null || { echo "Error: Failed to add repository to sources list."; exit 1; }
|
||||
update_required=1
|
||||
else
|
||||
echo "Repository already exists in sources list"
|
||||
fi
|
||||
|
||||
# update apt package list if required
|
||||
if [ "$update_required" == "1" ]; then
|
||||
sudo apt-get update || { echo "Error: Failed to update apt"; exit 1; }
|
||||
fi
|
||||
|
||||
echo "OK"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Invalid action: $action"
|
||||
echo "Usage: $0 <action> [parameters...]"
|
||||
echo "Actions:"
|
||||
echo " sudoers <file> Install a sudoers file"
|
||||
echo " packages <packages> Install aptitude package(s)"
|
||||
echo " user <name> <password> Add user non-interactively"
|
||||
echo " config <source <destination> Applies a config file"
|
||||
echo " javascript <source> <destination> Applies a JavaScript file"
|
||||
echo " plugin <source <destination> Copies a plugin directory"
|
||||
echo " sudoers <file> Install a sudoers file"
|
||||
echo " packages <packages> Install aptitude package(s)"
|
||||
echo " user <name> <password> Add user non-interactively"
|
||||
echo " config <source <destination> Applies a config file"
|
||||
echo " javascript <source> <destination> Applies a JavaScript file"
|
||||
echo " plugin <source> <destination> Copies a plugin directory"
|
||||
echo " keys <key_url> <keyring> <repo> <sources> Installs a GPG key for a third-party repo"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -151,6 +151,10 @@
|
||||
<td><small><code><span id="plugin-configuration" class="mb-0"></span></code></small></td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo _("Signed Packages"); ?></th>
|
||||
<td><small><code><span id="plugin-packages" class="mb-0"></span></code></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo _("Dependencies"); ?></th>
|
||||
<td><small><code><span id="plugin-dependencies" class="mb-0"></span></code></small></td>
|
||||
|
||||
Reference in New Issue
Block a user