90 lines
4.2 KiB
Markdown
90 lines
4.2 KiB
Markdown
|
|
# Plugin Protection
|
||
|
|
|
||
|
|
MokoWaaS 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, MokoWaaS sets the `protected` column to `1` in the `#__extensions` database table for both `mokowaas` and `pkg_mokowaas` 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, MokoWaaS injects JavaScript on the `com_plugins` and `com_installer` pages that hides any table row containing "mokowaas" or "MokoWaaS". 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('mokowaas') !== -1 || text.indexOf('MokoWaaS') !== -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: "MokoWaaS 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 MokoWaaS 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 MokoWaaS, 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 MokoWaaS (matching on element name `mokowaas` or `pkg_mokowaas`).
|
||
|
|
|
||
|
|
## 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 MokoWaaS 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_MokowaasInstallerScript`) 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 MokoWaaS 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
|
||
|
|
```
|