00d44256b4
Rebrand all 17 sub-extensions from mokowaas to mokosuite naming, including component, plugins, modules, task plugins, and webservices. Updates package manifest, workflows, docs, wiki, and issue templates. Adds new plg_system_mokosuite_license extension.
90 lines
4.3 KiB
Markdown
90 lines
4.3 KiB
Markdown
# Plugin Protection
|
|
|
|
MokoSuite uses multiple layers of protection to prevent accidental or unauthorized disabling and uninstallation. The master user retains full control over the plugin at all times.
|
|
|
|
## Protection Layers
|
|
|
|
### 1. Protected Flag (`protected=1`)
|
|
|
|
During installation and on every admin session, MokoSuite sets the `protected` column to `1` in the `#__extensions` database table for both `mokosuite` and `pkg_mokosuite` entries.
|
|
|
|
The Joomla framework itself enforces this flag: protected extensions cannot be disabled or uninstalled through the standard admin interface.
|
|
|
|
The `locked` column is set to `0` so the extension can still receive updates and configuration changes.
|
|
|
|
### 2. Self-Healing
|
|
|
|
The `ensureProtectedFlag()` method runs once per admin session (using a static flag to avoid repeated queries). If the `protected` column has been reset to `0` (e.g., by a database modification), it is automatically restored to `1`.
|
|
|
|
This runs in the `protectPlugin()` method, which is called from `onBeforeRender()` on every admin page load.
|
|
|
|
### 3. Hidden from Plugin List
|
|
|
|
For non-master users, MokoSuite injects JavaScript on the `com_plugins` and `com_installer` pages that hides any table row containing "mokosuite" or "MokoSuite". This prevents non-master users from seeing the plugin in the extension list.
|
|
|
|
The `hidePluginFromList()` method adds an inline script that runs on `DOMContentLoaded`:
|
|
|
|
```javascript
|
|
document.querySelectorAll('tr').forEach(function(row) {
|
|
var text = row.textContent || '';
|
|
if (text.indexOf('mokosuite') !== -1 || text.indexOf('MokoSuite') !== -1) {
|
|
row.style.display = 'none';
|
|
}
|
|
});
|
|
```
|
|
|
|
### 4. onExtensionBeforeSave Interception
|
|
|
|
The `onExtensionBeforeSave` event handler intercepts save attempts on the plugin configuration. If a non-master user attempts to save the plugin with `enabled = 0`, the handler:
|
|
|
|
1. Displays an error message: "MokoSuite cannot be disabled."
|
|
2. Forces `enabled` back to `1` on the table object
|
|
3. Returns `true` to allow the save to proceed (with the corrected value)
|
|
|
|
### 5. protectPlugin() -- Uninstall and Disable Blocking
|
|
|
|
The `protectPlugin()` method runs on every admin page request and checks for active uninstall or disable attempts:
|
|
|
|
**Uninstall blocking**: If the current request is to `com_installer` with task `manage.remove`, and the extension IDs include any MokoSuite extension, the request is blocked with an error message and a redirect back to the installer manage view.
|
|
|
|
**Disable blocking**: If the current request is to `com_plugins` with task `plugins.publish`, and the extension IDs include MokoSuite, the request is blocked with an error message and a redirect back to the plugins list.
|
|
|
|
The `isOurExtension()` helper method checks extension IDs against the database to determine if they belong to MokoSuite (matching on element name `mokosuite` or `pkg_mokosuite`).
|
|
|
|
## Master User Exemption
|
|
|
|
All protection checks call `isMasterUser()` first. If the current user is the designated master user (matching the configured `master_username`), all protections are bypassed. The master user can:
|
|
|
|
- See MokoSuite in the plugin and extension lists
|
|
- Disable the plugin via the configuration page
|
|
- Uninstall the plugin via the Extension Manager
|
|
- Modify all plugin settings
|
|
|
|
## Installation-Time Protection
|
|
|
|
The package installer script (`Pkg_MokosuiteInstallerScript`) and the plugin installer script both set `protected=1` during `postflight`:
|
|
|
|
- `enableAndLockPlugin()` sets `enabled=1`, `locked=1`, `protected=1` on the system plugin
|
|
- `protectExtensions()` sets `protected=1`, `locked=0` on all MokoSuite extensions (plugin and package)
|
|
|
|
This ensures protection is active immediately after installation, before the first admin page load triggers the self-healing logic.
|
|
|
|
## Summary of Protection Flow
|
|
|
|
```
|
|
Installation
|
|
-> postflight sets protected=1, enabled=1
|
|
|
|
Every admin page load (onBeforeRender)
|
|
-> protectPlugin()
|
|
-> ensureProtectedFlag() (once per session, restores protected=1 if needed)
|
|
-> if not master user:
|
|
-> block uninstall attempts (com_installer manage.remove)
|
|
-> block disable attempts (com_plugins plugins.publish)
|
|
-> hidePluginFromList() for non-master users
|
|
|
|
Plugin config save (onExtensionBeforeSave)
|
|
-> if not master user and enabled=0:
|
|
-> force enabled=1, show error
|
|
```
|