security: protected status prevents disable/uninstall
Joomla: Repo Health / Access control (push) Has been cancelled
Joomla: Update Server / Update updates.xml (push) Has been cancelled
Joomla: Repo Health / Release configuration (push) Has been cancelled
Joomla: Repo Health / Scripts governance (push) Has been cancelled
Joomla: Repo Health / Repository health (push) Has been cancelled
Joomla: Repo Health / Access control (push) Has been cancelled
Joomla: Update Server / Update updates.xml (push) Has been cancelled
Joomla: Repo Health / Release configuration (push) Has been cancelled
Joomla: Repo Health / Scripts governance (push) Has been cancelled
Joomla: Repo Health / Repository health (push) Has been cancelled
- Set protected=1, locked=0 on MokoWaaS extensions via package script - Self-healing: plugin checks and restores protected flag each session - Block non-master disable via plugin list toggle (plugins.publish) - Block non-master uninstall via installer manage - Joomla framework natively enforces protected status (greys out toggles) - Master users can still manage settings and updates Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -985,6 +985,15 @@ class MokoWaaS extends CMSPlugin
|
||||
*/
|
||||
protected function protectPlugin()
|
||||
{
|
||||
// Ensure protected flag is set (self-healing — runs once per session)
|
||||
static $flagChecked = false;
|
||||
|
||||
if (!$flagChecked)
|
||||
{
|
||||
$flagChecked = true;
|
||||
$this->ensureProtectedFlag();
|
||||
}
|
||||
|
||||
if ($this->isMasterUser())
|
||||
{
|
||||
return;
|
||||
@@ -993,7 +1002,7 @@ class MokoWaaS extends CMSPlugin
|
||||
$option = $this->app->input->get('option', '');
|
||||
$task = $this->app->input->get('task', '');
|
||||
|
||||
// Block non-master from disabling or uninstalling MokoWaaS
|
||||
// Block non-master from uninstalling MokoWaaS
|
||||
if ($option === 'com_installer' && strpos($task, 'manage.remove') !== false)
|
||||
{
|
||||
$cid = $this->app->input->get('cid', [], 'array');
|
||||
@@ -1004,6 +1013,49 @@ class MokoWaaS extends CMSPlugin
|
||||
$this->app->redirect('index.php?option=com_installer&view=manage');
|
||||
}
|
||||
}
|
||||
|
||||
// Block non-master from disabling via list toggle
|
||||
if ($option === 'com_plugins' && strpos($task, 'plugins.publish') !== false)
|
||||
{
|
||||
$cid = $this->app->input->get('cid', [], 'array');
|
||||
|
||||
if ($this->isOurExtension($cid))
|
||||
{
|
||||
$this->app->enqueueMessage('MokoWaaS cannot be disabled.', 'error');
|
||||
$this->app->redirect('index.php?option=com_plugins');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the protected flag is set on MokoWaaS extensions in the DB.
|
||||
*
|
||||
* Sets protected=1, locked=0 so the extension can't be disabled or
|
||||
* uninstalled but can still receive updates and config changes.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 02.03.10
|
||||
*/
|
||||
protected function ensureProtectedFlag()
|
||||
{
|
||||
try
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__extensions'))
|
||||
->set($db->quoteName('protected') . ' = 1')
|
||||
->set($db->quoteName('locked') . ' = 0')
|
||||
->where('(' . $db->quoteName('element') . ' = ' . $db->quote('mokowaas')
|
||||
. ' OR ' . $db->quoteName('element') . ' = ' . $db->quote('pkg_mokowaas') . ')')
|
||||
->where($db->quoteName('protected') . ' = 0');
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
}
|
||||
catch (\Throwable $e)
|
||||
{
|
||||
// Non-critical
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,9 @@ class Pkg_MokowaasInstallerScript
|
||||
$this->enablePlugin('system', 'mokowaas');
|
||||
$this->enablePlugin('webservices', 'mokowaas');
|
||||
|
||||
// Mark MokoWaaS extensions as protected (prevents disable/uninstall at framework level)
|
||||
$this->protectExtensions();
|
||||
|
||||
// Trigger heartbeat registration
|
||||
$this->sendHeartbeat();
|
||||
}
|
||||
@@ -71,6 +74,36 @@ class Pkg_MokowaasInstallerScript
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the protected flag on all MokoWaaS extensions.
|
||||
*
|
||||
* Joomla's protected flag prevents disabling and uninstalling at the
|
||||
* framework level — no plugin-side interception needed.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 02.03.10
|
||||
*/
|
||||
private function protectExtensions(): void
|
||||
{
|
||||
try
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__extensions'))
|
||||
->set($db->quoteName('protected') . ' = 1')
|
||||
->set($db->quoteName('locked') . ' = 0')
|
||||
->where('(' . $db->quoteName('element') . ' = ' . $db->quote('mokowaas')
|
||||
. ' OR ' . $db->quoteName('element') . ' = ' . $db->quote('pkg_mokowaas') . ')');
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
}
|
||||
catch (\Throwable $e)
|
||||
{
|
||||
Log::add('Error protecting MokoWaaS extensions: ' . $e->getMessage(), Log::WARNING, 'jerror');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send heartbeat to the MokoWaaS monitoring receiver.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user