Merge pull request 'fix: second version_set_platform pass before release commit' (#66) from dev into main
Universal: Cascade Main → Dev / Cascade main → branches (push) Has been cancelled
Joomla: Repo Health / Access control (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
Universal: Cascade Main → Dev / Cascade main → branches (push) Has been cancelled
Joomla: Repo Health / Access control (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
This commit was merged in pull request #66.
This commit is contained in:
@@ -351,9 +351,16 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
|
||||||
|
|
||||||
# Final version consistency check before commit
|
# Re-align all version files (second pass catches anything the build touched)
|
||||||
|
php /tmp/moko-platform-api/cli/version_set_platform.php \
|
||||||
|
--path . --version "$VERSION" --branch main 2>/dev/null || true
|
||||||
php /tmp/moko-platform-api/cli/version_check.php --path . --fix 2>/dev/null || true
|
php /tmp/moko-platform-api/cli/version_check.php --path . --fix 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "=== Pre-commit version check ==="
|
||||||
|
php /tmp/moko-platform-api/cli/version_check.php --path . || true
|
||||||
|
echo "=== Files changed ==="
|
||||||
|
git status --short
|
||||||
|
|
||||||
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
|
||||||
git config --local user.name "gitea-actions[bot]"
|
git config --local user.name "gitea-actions[bot]"
|
||||||
git remote set-url origin "https://jmiller:${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
git remote set-url origin "https://jmiller:${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
DEFGROUP: Joomla.Plugin
|
DEFGROUP: Joomla.Plugin
|
||||||
INGROUP: MokoWaaS
|
INGROUP: MokoWaaS
|
||||||
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS
|
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS
|
||||||
VERSION: 02.13.00
|
VERSION: 02.13.01
|
||||||
PATH: /README.md
|
PATH: /README.md
|
||||||
BRIEF: MokoWaaS platform plugin for Joomla
|
BRIEF: MokoWaaS platform plugin for Joomla
|
||||||
-->
|
-->
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<license>GPL-3.0-or-later</license>
|
<license>GPL-3.0-or-later</license>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||||
<version>02.13.00</version>
|
<version>02.13.01</version>
|
||||||
<description>Minimal API-only component for MokoWaaS. Provides REST endpoints for site health, cache, updates, and backups.</description>
|
<description>Minimal API-only component for MokoWaaS. Provides REST endpoints for site health, cache, updates, and backups.</description>
|
||||||
<namespace path="api/src">Moko\Component\MokoWaaS\Api</namespace>
|
<namespace path="api/src">Moko\Component\MokoWaaS\Api</namespace>
|
||||||
<administration>
|
<administration>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<license>GNU General Public License version 3 or later; see LICENSE.md</license>
|
<license>GNU General Public License version 3 or later; see LICENSE.md</license>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||||
<version>02.13.00</version>
|
<version>02.13.01</version>
|
||||||
<description>This plugin rebrands the Joomla system interface with MokoWaaS identity. It applies language overrides and ensures consistent branding across the platform.</description>
|
<description>This plugin rebrands the Joomla system interface with MokoWaaS identity. It applies language overrides and ensures consistent branding across the platform.</description>
|
||||||
<namespace path=".">Moko\Plugin\System\MokoWaaS</namespace>
|
<namespace path=".">Moko\Plugin\System\MokoWaaS</namespace>
|
||||||
<scriptfile>script.php</scriptfile>
|
<scriptfile>script.php</scriptfile>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<license>GPL-3.0-or-later</license>
|
<license>GPL-3.0-or-later</license>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||||
<version>02.13.00</version>
|
<version>02.13.01</version>
|
||||||
<description>Joomla Web Services API routes for MokoWaaS site management — health checks, cache, updates, backups, and site info.</description>
|
<description>Joomla Web Services API routes for MokoWaaS site management — health checks, cache, updates, backups, and site info.</description>
|
||||||
<namespace path="src">Moko\Plugin\WebServices\MokoWaaS</namespace>
|
<namespace path="src">Moko\Plugin\WebServices\MokoWaaS</namespace>
|
||||||
<files>
|
<files>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<extension type="package" method="upgrade">
|
<extension type="package" method="upgrade">
|
||||||
<name>MokoWaaS</name>
|
<name>MokoWaaS</name>
|
||||||
<packagename>mokowaas</packagename>
|
<packagename>mokowaas</packagename>
|
||||||
<version>02.13.00</version>
|
<version>02.13.01</version>
|
||||||
<creationDate>2026-05-23</creationDate>
|
<creationDate>2026-05-23</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
# API Endpoints
|
||||||
|
|
||||||
|
MokoWaaS provides 6 remote management endpoints accessible via query string parameter. All endpoints require HTTPS and Bearer token authentication.
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
All endpoints require the `health_api_token` as a Bearer token in the Authorization header:
|
||||||
|
|
||||||
|
```
|
||||||
|
Authorization: Bearer <health_api_token>
|
||||||
|
```
|
||||||
|
|
||||||
|
The token is auto-generated during plugin installation and stored as a read-only parameter in the plugin configuration. It can also be passed as a `token` query parameter as a fallback.
|
||||||
|
|
||||||
|
Token validation uses `hash_equals()` for timing-safe comparison. If no token is configured, the endpoint returns HTTP 503. An invalid token returns HTTP 401.
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
### 1. Health Check
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /?mokowaas=health
|
||||||
|
```
|
||||||
|
|
||||||
|
Runs 16 diagnostic checks and returns a comprehensive health report. See [Health Monitoring](Health-Monitoring) for full documentation of all checks and response format.
|
||||||
|
|
||||||
|
**Response**: JSON object with `status` (`ok`/`degraded`/`error`), `reason`, `timestamp`, `checks`, and `meta`.
|
||||||
|
|
||||||
|
**HTTP Status**: 200 (ok/degraded), 503 (error).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Site Info
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /?mokowaas=info
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns a compact summary of the Joomla site.
|
||||||
|
|
||||||
|
**Response**:
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `site_name` | Joomla site name |
|
||||||
|
| `site_url` | Site root URL |
|
||||||
|
| `joomla_version` | Joomla CMS version |
|
||||||
|
| `php_version` | PHP version |
|
||||||
|
| `db_type` | Database driver (e.g. `pdomysql`) |
|
||||||
|
| `debug` | Whether debug mode is on |
|
||||||
|
| `sef` | Whether SEF URLs are enabled |
|
||||||
|
| `caching` | Whether caching is enabled |
|
||||||
|
| `articles` | Total article count |
|
||||||
|
| `users` | Total user count |
|
||||||
|
| `extensions` | Number of enabled extensions |
|
||||||
|
| `brand` | Configured brand name |
|
||||||
|
| `plugin_version` | MokoWaaS plugin version |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Remote Install
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /?mokowaas=install
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{"url": "https://example.com/extension.zip"}
|
||||||
|
```
|
||||||
|
|
||||||
|
Downloads and installs a Joomla extension from the provided URL. The extension is downloaded to a temporary directory, extracted, and installed using Joomla's installer API.
|
||||||
|
|
||||||
|
**Response**: JSON object with `status`, `extension` name, and `message`.
|
||||||
|
|
||||||
|
**HTTP Status**: 200 (success), 400 (missing URL), 405 (not POST), 500 (install failed).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Update Check
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /?mokowaas=update
|
||||||
|
```
|
||||||
|
|
||||||
|
Clears the Joomla update cache and triggers a fresh update check via `Updater::findUpdates()`.
|
||||||
|
|
||||||
|
**Response**:
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok` |
|
||||||
|
| `updates_found` | Number of available updates |
|
||||||
|
| `message` | Human-readable summary |
|
||||||
|
|
||||||
|
**HTTP Status**: 200 (success), 405 (not POST), 500 (failed).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Cache Clear
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /?mokowaas=cache
|
||||||
|
```
|
||||||
|
|
||||||
|
Clears the Joomla site cache, admin cache, and PHP OPcache (if available).
|
||||||
|
|
||||||
|
**Response**:
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok` |
|
||||||
|
| `message` | `Cache cleared` |
|
||||||
|
|
||||||
|
**HTTP Status**: 200 (success), 405 (not POST), 500 (failed).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. Backup (Akeeba)
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /?mokowaas=backup
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{"profile": 1}
|
||||||
|
```
|
||||||
|
|
||||||
|
Triggers an Akeeba Backup using the specified profile (defaults to profile 1). Requires Akeeba Backup to be installed.
|
||||||
|
|
||||||
|
**Response**:
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `started` |
|
||||||
|
| `profile` | Backup profile ID used |
|
||||||
|
| `message` | `Backup started` |
|
||||||
|
|
||||||
|
**HTTP Status**: 200 (started), 404 (Akeeba not installed), 405 (not POST), 500 (failed), 501 (Akeeba Engine not loadable).
|
||||||
|
|
||||||
|
## Error Responses
|
||||||
|
|
||||||
|
All endpoints return errors in a consistent format:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "Error description",
|
||||||
|
"message": "Additional detail (optional)"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Error Codes
|
||||||
|
|
||||||
|
| HTTP Status | Meaning |
|
||||||
|
|---|---|
|
||||||
|
| 400 | Bad request (unknown action, missing parameters) |
|
||||||
|
| 401 | Invalid or missing authentication token |
|
||||||
|
| 405 | Wrong HTTP method (e.g. GET when POST is required) |
|
||||||
|
| 500 | Server error during operation |
|
||||||
|
| 503 | No API token configured |
|
||||||
|
|
||||||
|
## Unknown Actions
|
||||||
|
|
||||||
|
Requesting an unknown action returns HTTP 400 with the list of available actions:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "Unknown action",
|
||||||
|
"action": "invalid",
|
||||||
|
"available": ["health", "install", "update", "cache", "backup", "info"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Joomla REST API Routes
|
||||||
|
|
||||||
|
In addition to the query-string endpoints above, MokoWaaS registers standard Joomla API routes via the `plg_webservices_mokowaas` plugin:
|
||||||
|
|
||||||
|
| Route | Controller |
|
||||||
|
|---|---|
|
||||||
|
| `GET /api/v1/mokowaas/health` | HealthController |
|
||||||
|
| `POST /api/v1/mokowaas/cache` | CacheController |
|
||||||
|
| `POST /api/v1/mokowaas/update` | UpdateController |
|
||||||
|
|
||||||
|
These routes use Joomla's standard API authentication (API token in `X-Joomla-Token` header) and are useful for integrations that already use the Joomla API framework.
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
# Configuration
|
||||||
|
|
||||||
|
All MokoWaaS settings are managed in the Joomla plugin configuration under **System > Plugins > System - MokoWaaS**. Settings are organized into tabs (fieldsets).
|
||||||
|
|
||||||
|
## Basic (Branding)
|
||||||
|
|
||||||
|
| Parameter | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `enable_branding` | Yes/No | Yes | Enable white-label branding (language overrides, logos, colors) |
|
||||||
|
| `brand_name` | Text | `MokoWaaS` | Brand name displayed throughout the admin interface |
|
||||||
|
| `company_name` | Text | `Moko Consulting` | Company name used in footers and copyright notices |
|
||||||
|
| `support_url` | URL | `https://mokoconsulting.tech` | Support link shown on the admin login page and dashboard |
|
||||||
|
|
||||||
|
## WaaS Access
|
||||||
|
|
||||||
|
Controls the master user system that designates a single operator account.
|
||||||
|
|
||||||
|
| Parameter | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `enforce_master_user` | Yes/No | Yes | Enable master user enforcement; non-master Super Admins are restricted |
|
||||||
|
| `master_username` | Text | `mokoconsulting` | Username of the designated master operator |
|
||||||
|
| `master_email` | Email | `webmaster@mokoconsulting.tech` | Email address of the master user (for verification) |
|
||||||
|
| `emergency_access` | Yes/No | Yes | Enable emergency access via database password + file-based 2FA |
|
||||||
|
| `allowed_ips_display` | Display | -- | Read-only display of whitelisted IP addresses for emergency access |
|
||||||
|
|
||||||
|
## Maintenance
|
||||||
|
|
||||||
|
| Parameter | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `dev_mode` | Yes/No | No | Disable Joomla caching at runtime (does not modify `configuration.php`) |
|
||||||
|
| `reset_hits` | Yes/No | No | Reset article hit counters on next admin load |
|
||||||
|
| `delete_versions` | Yes/No | No | Purge content version history on next admin load |
|
||||||
|
|
||||||
|
## Visual Branding
|
||||||
|
|
||||||
|
| Parameter | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `color_primary` | Color | `#1a2744` | Primary brand color (buttons, accents) |
|
||||||
|
| `color_sidebar` | Color | `#0f1b2d` | Admin sidebar background color |
|
||||||
|
| `color_header` | Color | `#1a2744` | Admin header bar color |
|
||||||
|
| `color_link` | Color | `#0051ad` | Link text color |
|
||||||
|
| `brand_icon` | Text | -- | FontAwesome unicode code point (e.g. `f6d5`) for the brand icon |
|
||||||
|
| `custom_css` | Textarea | -- | Custom CSS injected into every admin page |
|
||||||
|
|
||||||
|
## Tenant Restrictions
|
||||||
|
|
||||||
|
Controls what non-master Super Admin users can access.
|
||||||
|
|
||||||
|
| Parameter | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `restrict_installer` | Yes/No | Yes | Block access to Extension Manager for non-master users |
|
||||||
|
| `hide_sysinfo` | Yes/No | Yes | Hide System Information page from non-master users |
|
||||||
|
| `restrict_global_config` | Yes/No | Yes | Block access to Global Configuration for non-master users |
|
||||||
|
| `restrict_template_editing` | Yes/No | Yes | Prevent non-master users from editing template files |
|
||||||
|
| `disable_install_url` | Yes/No | Yes | Remove the "Install from URL" tab in Extension Manager |
|
||||||
|
| `hidden_menu_items` | Textarea | -- | Comma-separated list of admin menu item IDs to hide from non-master users |
|
||||||
|
|
||||||
|
## Site Aliases
|
||||||
|
|
||||||
|
Multi-domain support. See [Site Aliases](Site-Aliases) for full documentation.
|
||||||
|
|
||||||
|
| Parameter | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `primary_domain` | Text | -- | The canonical domain for the site (e.g. `waas.dev.mokoconsulting.tech`) |
|
||||||
|
| `site_aliases` | Subform | -- | Repeatable table of alias domains with per-alias settings |
|
||||||
|
|
||||||
|
Each alias entry contains:
|
||||||
|
|
||||||
|
| Field | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `domain` | Text | -- | Alias domain name (e.g. `www.example.com`) |
|
||||||
|
| `offline` | Yes/No | No | Show offline page for this alias |
|
||||||
|
| `offline_message` | Textarea | -- | Custom offline message (shown when `offline` is Yes) |
|
||||||
|
| `robots` | List | `index, follow` | Robots meta directive for this alias |
|
||||||
|
| `redirect_backend` | Yes/No | Yes | Redirect admin requests on this alias to the primary domain |
|
||||||
|
|
||||||
|
## Diagnostics
|
||||||
|
|
||||||
|
| Parameter | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `health_api_token` | Text (read-only) | -- | Auto-generated Bearer token for API authentication. Provisioned on install/update. Cannot be manually edited. |
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
| Parameter | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `force_https` | Yes/No | Yes | Redirect all HTTP requests to HTTPS (301 redirect) |
|
||||||
|
| `admin_session_timeout` | Number | `60` | Idle timeout in minutes for admin sessions (0 = use Joomla default). Master user is exempt. |
|
||||||
|
| `password_min_length` | Number | `12` | Minimum password length for user accounts |
|
||||||
|
| `password_require_uppercase` | Yes/No | Yes | Require at least one uppercase letter |
|
||||||
|
| `password_require_number` | Yes/No | Yes | Require at least one digit |
|
||||||
|
| `password_require_special` | Yes/No | Yes | Require at least one special character |
|
||||||
|
| `upload_allowed_types` | Text | `jpg,jpeg,png,gif,webp,svg,pdf,doc,docx,xls,xlsx` | Comma-separated list of allowed upload file extensions |
|
||||||
|
| `upload_max_size_mb` | Number | `100` | Maximum upload file size in megabytes |
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
# Grafana Integration
|
||||||
|
|
||||||
|
MokoWaaS integrates with a Grafana monitoring stack hosted at `bench.mokoconsulting.tech`. The integration is automatic: on install or update, the plugin sends a heartbeat that provisions a Grafana datasource for the site.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
MokoWaaS Plugin (Joomla)
|
||||||
|
|
|
||||||
|
| POST /api/waas-heartbeat/register
|
||||||
|
v
|
||||||
|
Heartbeat Receiver (bench.mokoconsulting.tech)
|
||||||
|
|
|
||||||
|
|-- Writes Grafana Infinity datasource YAML
|
||||||
|
|-- Restarts Grafana to pick up new datasource
|
||||||
|
|-- Sends ntfy notification (mokowaas-heartbeat topic)
|
||||||
|
v
|
||||||
|
Grafana Dashboard
|
||||||
|
|
|
||||||
|
| GET /?mokowaas=health (per site, on schedule)
|
||||||
|
v
|
||||||
|
Health JSON from each registered site
|
||||||
|
```
|
||||||
|
|
||||||
|
## Heartbeat Registration
|
||||||
|
|
||||||
|
### When It Fires
|
||||||
|
|
||||||
|
The heartbeat is sent automatically during:
|
||||||
|
|
||||||
|
- Plugin installation (`postflight` with type `install`)
|
||||||
|
- Plugin update (`postflight` with type `update`)
|
||||||
|
- Package installation (via `Pkg_MokowaasInstallerScript::sendHeartbeat()`)
|
||||||
|
|
||||||
|
### Payload
|
||||||
|
|
||||||
|
The plugin sends a POST request to `https://bench.mokoconsulting.tech/api/waas-heartbeat/register` with:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"site_url": "https://example.com",
|
||||||
|
"site_name": "Example Site",
|
||||||
|
"health_token": "<health_api_token>",
|
||||||
|
"action": "register"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Authentication uses a shared secret sent in the `X-MokoWaaS-Key` header.
|
||||||
|
|
||||||
|
### What the Receiver Does
|
||||||
|
|
||||||
|
On receiving a registration request, the heartbeat receiver:
|
||||||
|
|
||||||
|
1. Validates the `X-MokoWaaS-Key` header
|
||||||
|
2. Generates a unique datasource UID from the site URL
|
||||||
|
3. Writes a Grafana Infinity datasource YAML file to the Grafana provisioning directory
|
||||||
|
4. Restarts Grafana to load the new datasource
|
||||||
|
5. Sends an ntfy notification to the `mokowaas-heartbeat` topic with registration details
|
||||||
|
|
||||||
|
The datasource YAML configures a Grafana Infinity datasource that polls `/?mokowaas=health` on the registered site using the provided Bearer token.
|
||||||
|
|
||||||
|
### Response
|
||||||
|
|
||||||
|
On success (HTTP 200):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"ds_uid": "mokowaas-example-com"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ds_uid` is logged in the Joomla admin message queue for reference.
|
||||||
|
|
||||||
|
## Grafana Dashboard
|
||||||
|
|
||||||
|
The MokoWaaS Grafana dashboard is organized into 9 rows covering all health metrics:
|
||||||
|
|
||||||
|
| Row | Panels |
|
||||||
|
|---|---|
|
||||||
|
| 1. Overview | Overall status, uptime, plugin version, Joomla version |
|
||||||
|
| 2. Database | Connectivity, latency, driver, user count |
|
||||||
|
| 3. Filesystem | Disk space, writable directories, site size |
|
||||||
|
| 4. Extensions | Extension counts by type, pending updates |
|
||||||
|
| 5. Backup | Last backup status, age, Akeeba health |
|
||||||
|
| 6. Security | Admin Tools WAF, SSL certificate, blocked requests |
|
||||||
|
| 7. Content | Article counts, categories, user activity |
|
||||||
|
| 8. Infrastructure | Cache status, mail config, scheduled tasks, error log |
|
||||||
|
| 9. Configuration | SEO settings, template info, config drift |
|
||||||
|
|
||||||
|
Each row contains panels that query the site's Infinity datasource using JSONPath expressions to extract values from the health check response.
|
||||||
|
|
||||||
|
## ntfy Notifications
|
||||||
|
|
||||||
|
Registration events trigger a notification to the `mokowaas-heartbeat` ntfy topic. Notifications include:
|
||||||
|
|
||||||
|
- Site URL
|
||||||
|
- Site name
|
||||||
|
- Registration action (new or update)
|
||||||
|
- Datasource UID
|
||||||
|
|
||||||
|
Subscribe to notifications at `https://ntfy.sh/mokowaas-heartbeat` or use the ntfy app.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Heartbeat failed: connection error
|
||||||
|
|
||||||
|
The receiver at `bench.mokoconsulting.tech` may be unreachable. Check:
|
||||||
|
|
||||||
|
- DNS resolution for `bench.mokoconsulting.tech`
|
||||||
|
- Outbound HTTPS connectivity from the Joomla server
|
||||||
|
- Firewall rules allowing outbound port 443
|
||||||
|
|
||||||
|
Heartbeat failures are logged as warnings in Joomla's log and displayed in the admin message queue. They do not block plugin installation.
|
||||||
|
|
||||||
|
### Datasource not appearing in Grafana
|
||||||
|
|
||||||
|
- Verify the heartbeat completed successfully (check Joomla admin messages after install)
|
||||||
|
- Check the Grafana provisioning directory on `bench.mokoconsulting.tech`
|
||||||
|
- Ensure Grafana was restarted after provisioning
|
||||||
|
- Verify the health endpoint is accessible from the Grafana server
|
||||||
|
|
||||||
|
### Health data not loading in dashboard
|
||||||
|
|
||||||
|
- Confirm the `health_api_token` matches between the plugin configuration and the Grafana datasource
|
||||||
|
- Test the health endpoint directly: `curl -sk -H "Authorization: Bearer <token>" "https://example.com/?mokowaas=health"`
|
||||||
|
- Check for SSL certificate issues between the Grafana server and the monitored site
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Health Endpoint
|
||||||
|
|
||||||
|
## Stable Release: 02.01.37
|
||||||
|
|
||||||
|
16 diagnostic checks via /?mokowaas=health (token-authenticated, HTTPS-only).
|
||||||
|
|
||||||
|
### Checks
|
||||||
|
|
||||||
|
Core: database, filesystem, cache, extensions
|
||||||
|
Security: backup (Akeeba), security (Admin Tools), SSL certificate
|
||||||
|
Operations: scheduled tasks, error log, database size, mail
|
||||||
|
Content: articles, categories, users, sessions, failed logins
|
||||||
|
Config: SEO, templates, debug mode, force SSL, caching
|
||||||
|
|
||||||
|
### Grafana Dashboard (9 rows)
|
||||||
|
|
||||||
|
Site Overview | Health Metrics | Infrastructure | Backup | Security | SSL/Cron | Content/Users | Mail/SEO/Config | DB/Errors
|
||||||
|
|
||||||
|
### Heartbeat
|
||||||
|
|
||||||
|
Auto-registers with Grafana via bench.mokoconsulting.tech/api/waas-heartbeat/register
|
||||||
|
ntfy notifications on mokowaas-heartbeat topic
|
||||||
|
|
||||||
|
### Plugin Protection
|
||||||
|
|
||||||
|
Hidden from non-master users, settings blocked, self-healing lock, uninstall blocked.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|---|---|
|
||||||
|
| Minimum Version | 02.01.37 |
|
||||||
|
| Platform | joomla |
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
# Health Monitoring
|
||||||
|
|
||||||
|
MokoWaaS includes a built-in health monitoring system that runs 16 diagnostic checks against the Joomla site. Results are returned as a JSON payload via the `/?mokowaas=health` endpoint.
|
||||||
|
|
||||||
|
## Endpoint
|
||||||
|
|
||||||
|
```
|
||||||
|
GET https://example.com/?mokowaas=health
|
||||||
|
Authorization: Bearer <health_api_token>
|
||||||
|
```
|
||||||
|
|
||||||
|
The `health_api_token` is auto-generated during plugin installation and stored as a read-only plugin parameter. See [API Endpoints](API-Endpoints) for authentication details.
|
||||||
|
|
||||||
|
## Response Structure
|
||||||
|
|
||||||
|
The response includes an overall status, a human-readable reason string, a UTC timestamp, individual check results, and instance metadata.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | Overall status: `ok`, `degraded`, or `error` |
|
||||||
|
| `reason` | Human-readable summary of issues (null when status is `ok`) |
|
||||||
|
| `timestamp` | ISO 8601 UTC timestamp |
|
||||||
|
| `checks` | Object containing all 16 check results |
|
||||||
|
| `meta` | Instance metadata (brand, versions, server name) |
|
||||||
|
|
||||||
|
### Status Determination
|
||||||
|
|
||||||
|
- If any check returns `error`, the overall status is `error` and the HTTP status code is **503**.
|
||||||
|
- If any check returns `degraded` (and none are `error`), the overall status is `degraded` with HTTP **200**.
|
||||||
|
- Otherwise the overall status is `ok` with HTTP **200**.
|
||||||
|
|
||||||
|
## The 16 Checks
|
||||||
|
|
||||||
|
### 1. database
|
||||||
|
|
||||||
|
Tests database connectivity and query latency.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok` or `error` |
|
||||||
|
| `latency_ms` | Query round-trip time in milliseconds |
|
||||||
|
| `driver` | Database driver name (e.g. `mysqli`, `pdomysql`) |
|
||||||
|
| `users` | Total user count (sanity check) |
|
||||||
|
|
||||||
|
### 2. filesystem
|
||||||
|
|
||||||
|
Checks writable directories and disk space.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok`, `degraded` (low disk), or `error` (not writable) |
|
||||||
|
| `tmp_writable` | Whether `/tmp` is writable |
|
||||||
|
| `log_writable` | Whether `/administrator/logs` is writable |
|
||||||
|
| `cache_writable` | Whether `/cache` is writable |
|
||||||
|
| `free_disk_mb` | Free disk space in MB |
|
||||||
|
| `total_disk_mb` | Total disk space in MB |
|
||||||
|
| `site_size_mb` | Estimated site size in MB (images, media, tmp, cache, logs) |
|
||||||
|
|
||||||
|
Degraded when free disk is below 100 MB. Error when required directories are not writable.
|
||||||
|
|
||||||
|
### 3. cache
|
||||||
|
|
||||||
|
Reports Joomla cache configuration.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | Always `ok` |
|
||||||
|
| `enabled` | Whether Joomla caching is active |
|
||||||
|
| `handler` | Cache handler type (e.g. `file`, `redis`) |
|
||||||
|
|
||||||
|
### 4. extensions
|
||||||
|
|
||||||
|
Counts enabled extensions by type and checks for pending updates.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok` or `degraded` (pending updates) |
|
||||||
|
| `by_type` | Object with counts per extension type |
|
||||||
|
| `pending_updates` | Number of available extension updates |
|
||||||
|
|
||||||
|
### 5. backup (Akeeba)
|
||||||
|
|
||||||
|
Checks Akeeba Backup status.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok`, `degraded`, or `error` |
|
||||||
|
| `last_status` | Status of the last backup record (`complete`, `fail`, etc.) |
|
||||||
|
| `days_since` | Days since the last backup |
|
||||||
|
| `message` | Human-readable backup status |
|
||||||
|
|
||||||
|
Degraded when the last backup is older than 7 days or did not complete successfully.
|
||||||
|
|
||||||
|
### 6. security (Admin Tools)
|
||||||
|
|
||||||
|
Checks Admin Tools WAF status if installed.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok`, `degraded`, or `error` |
|
||||||
|
| `waf_enabled` | Whether the Web Application Firewall is active |
|
||||||
|
| `blocked_24h` | Number of blocked requests in the last 24 hours |
|
||||||
|
|
||||||
|
### 7. ssl
|
||||||
|
|
||||||
|
Checks SSL certificate validity and expiration.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok`, `degraded`, or `error` |
|
||||||
|
| `days_left` | Days until certificate expiration |
|
||||||
|
| `issuer` | Certificate issuer |
|
||||||
|
| `valid_from` | Certificate start date |
|
||||||
|
| `valid_to` | Certificate expiration date |
|
||||||
|
|
||||||
|
Degraded when the certificate expires within 30 days.
|
||||||
|
|
||||||
|
### 8. cron (Scheduled Tasks)
|
||||||
|
|
||||||
|
Checks Joomla scheduled task execution.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok` or `degraded` |
|
||||||
|
| `total_tasks` | Total number of scheduled tasks |
|
||||||
|
| `failed_24h` | Tasks that failed in the last 24 hours |
|
||||||
|
|
||||||
|
### 9. errors (Error Log)
|
||||||
|
|
||||||
|
Analyzes recent Joomla error log entries.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok` or `degraded` |
|
||||||
|
| `recent_errors` | Count of recent error log entries |
|
||||||
|
| `last_error` | Most recent error message |
|
||||||
|
|
||||||
|
### 10. db_size
|
||||||
|
|
||||||
|
Reports database size metrics.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok` or `degraded` |
|
||||||
|
| `total_mb` | Total database size in MB |
|
||||||
|
| `tables` | Number of database tables |
|
||||||
|
|
||||||
|
### 11. content
|
||||||
|
|
||||||
|
Reports content statistics.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | Always `ok` |
|
||||||
|
| `articles` | Total article count |
|
||||||
|
| `categories` | Total category count |
|
||||||
|
| `published` | Number of published articles |
|
||||||
|
| `unpublished` | Number of unpublished articles |
|
||||||
|
|
||||||
|
### 12. users (User Activity)
|
||||||
|
|
||||||
|
Reports user statistics.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | Always `ok` |
|
||||||
|
| `total` | Total user count |
|
||||||
|
| `active_30d` | Users active in the last 30 days |
|
||||||
|
| `blocked` | Number of blocked user accounts |
|
||||||
|
|
||||||
|
### 13. mail
|
||||||
|
|
||||||
|
Checks Joomla mail configuration.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok` or `degraded` |
|
||||||
|
| `mailer` | Mail handler type (e.g. `smtp`, `mail`, `sendmail`) |
|
||||||
|
| `from` | Configured sender address |
|
||||||
|
|
||||||
|
### 14. seo
|
||||||
|
|
||||||
|
Checks SEO configuration.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok` or `degraded` |
|
||||||
|
| `sef` | Whether SEF URLs are enabled |
|
||||||
|
| `sef_rewrite` | Whether URL rewriting is enabled |
|
||||||
|
| `sitemap` | Whether a sitemap is detected |
|
||||||
|
|
||||||
|
### 15. template
|
||||||
|
|
||||||
|
Reports active template information.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | Always `ok` |
|
||||||
|
| `site_template` | Active frontend template name |
|
||||||
|
| `admin_template` | Active admin template name |
|
||||||
|
|
||||||
|
### 16. config (Config Drift)
|
||||||
|
|
||||||
|
Detects configuration anomalies.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `status` | `ok` or `degraded` |
|
||||||
|
| `issues` | Array of detected configuration problems |
|
||||||
|
|
||||||
|
Checks for issues such as debug mode enabled in production, error reporting set too high, or default database prefix still in use.
|
||||||
|
|
||||||
|
## Example Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "degraded",
|
||||||
|
"reason": "2 extension updates available; SSL expires in 14 days",
|
||||||
|
"timestamp": "2026-05-24T12:00:00Z",
|
||||||
|
"checks": {
|
||||||
|
"database": {
|
||||||
|
"status": "ok",
|
||||||
|
"latency_ms": 1.23,
|
||||||
|
"driver": "pdomysql",
|
||||||
|
"users": 5
|
||||||
|
},
|
||||||
|
"filesystem": {
|
||||||
|
"status": "ok",
|
||||||
|
"tmp_writable": true,
|
||||||
|
"log_writable": true,
|
||||||
|
"cache_writable": true,
|
||||||
|
"free_disk_mb": 4500,
|
||||||
|
"total_disk_mb": 20000,
|
||||||
|
"site_size_mb": 320
|
||||||
|
},
|
||||||
|
"ssl": {
|
||||||
|
"status": "degraded",
|
||||||
|
"days_left": 14,
|
||||||
|
"issuer": "Let's Encrypt",
|
||||||
|
"valid_to": "2026-06-07"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"brand": "MokoWaaS",
|
||||||
|
"plugin_version": "02.03.11",
|
||||||
|
"joomla_version": "5.2.4",
|
||||||
|
"php_version": "8.2.20",
|
||||||
|
"server_name": "Example Site",
|
||||||
|
"server_time": "2026-05-24T12:00:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
(Remaining checks omitted for brevity.)
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
The `meta` object is included in every health response:
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `brand` | Configured brand name |
|
||||||
|
| `plugin_version` | MokoWaaS plugin version |
|
||||||
|
| `joomla_version` | Joomla CMS version |
|
||||||
|
| `php_version` | PHP version |
|
||||||
|
| `server_name` | Joomla site name |
|
||||||
|
| `server_time` | Server UTC time |
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# MokoWaaS
|
||||||
|
|
||||||
|
MokoWaaS is a Joomla 5.x / 6.x extension package that provides a configurable white-label identity layer, tenant management, health monitoring, and remote administration API for the MokoWaaS platform.
|
||||||
|
|
||||||
|
Developed by [Moko Consulting](https://mokoconsulting.tech). Licensed under GPL-3.0-or-later.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **White-label branding** -- customizable brand name, colors, favicon, login page, and admin template theming
|
||||||
|
- **Master user enforcement** -- designate a single operator account with elevated privileges; restrict other Super Admins
|
||||||
|
- **Tenant restrictions** -- hide system info, block installer access, restrict global config and template editing, hide menu items
|
||||||
|
- **Site aliases** -- multi-domain support with per-alias offline mode, robots directives, and backend redirects
|
||||||
|
- **Health monitoring** -- 16 diagnostic checks exposed via authenticated JSON API
|
||||||
|
- **Remote management API** -- 6 endpoints for health, info, install, update, cache clear, and backup
|
||||||
|
- **Grafana integration** -- automatic heartbeat registration with Grafana Infinity datasource provisioning
|
||||||
|
- **Plugin protection** -- protected flag, self-healing, hidden from non-master users, blocks disable/uninstall
|
||||||
|
- **Security hardening** -- forced HTTPS, session timeouts, password policy, upload restrictions
|
||||||
|
- **Emergency access** -- file-based two-factor verification for master user recovery
|
||||||
|
- **Automatic updates** -- via Joomla update server hosted on Gitea
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
| Requirement | Minimum |
|
||||||
|
|---|---|
|
||||||
|
| Joomla | 5.0.0+ (5.x and 6.x supported) |
|
||||||
|
| PHP | 8.1.0+ |
|
||||||
|
|
||||||
|
## Package Contents
|
||||||
|
|
||||||
|
The `pkg_mokowaas` package installs three extensions:
|
||||||
|
|
||||||
|
| Extension | Type | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| `plg_system_mokowaas` | System Plugin | Core branding, restrictions, health checks, API endpoints |
|
||||||
|
| `com_mokowaas` | Component | REST API controllers (health, cache, update) |
|
||||||
|
| `plg_webservices_mokowaas` | Webservices Plugin | Registers Joomla API routes for `v1/mokowaas/*` |
|
||||||
|
|
||||||
|
## Wiki Pages
|
||||||
|
|
||||||
|
- [Configuration](Configuration) -- All plugin settings organized by tab
|
||||||
|
- [Health Monitoring](Health-Monitoring) -- The 16 diagnostic checks
|
||||||
|
- [Site Aliases](Site-Aliases) -- Multi-domain management
|
||||||
|
- [API Endpoints](API-Endpoints) -- The 6 remote management endpoints
|
||||||
|
- [Grafana Integration](Grafana-Integration) -- Monitoring dashboard setup
|
||||||
|
- [Plugin Protection](Plugin-Protection) -- Security measures preventing disable/uninstall
|
||||||
|
- [Installation](Installation) -- Step-by-step install and upgrade guide
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- **Repository**: [MokoWaaS on Gitea](https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS)
|
||||||
|
- **Update Server**: [updates.xml](https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/raw/branch/main/updates.xml)
|
||||||
|
- **Author**: [Moko Consulting](https://mokoconsulting.tech)
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
# Installation
|
||||||
|
|
||||||
|
MokoWaaS is distributed as a Joomla package (`pkg_mokowaas`) containing three extensions. It can be installed via the standard Joomla Extension Manager.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
| Requirement | Minimum |
|
||||||
|
|---|---|
|
||||||
|
| Joomla | 5.0.0+ |
|
||||||
|
| PHP | 8.1.0+ |
|
||||||
|
|
||||||
|
The installer checks both requirements during `preflight` and aborts with an error message if either is not met.
|
||||||
|
|
||||||
|
## Method 1: Upload Package File
|
||||||
|
|
||||||
|
1. Download the latest `pkg_mokowaas.zip` from the [Gitea Releases](https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases) page.
|
||||||
|
2. In Joomla admin, navigate to **System > Install > Extensions**.
|
||||||
|
3. On the **Upload Package File** tab, drag and drop or browse to select `pkg_mokowaas.zip`.
|
||||||
|
4. Click **Upload & Install**.
|
||||||
|
5. Verify the success message. The package installs three extensions:
|
||||||
|
- `plg_system_mokowaas` (System Plugin)
|
||||||
|
- `com_mokowaas` (Component)
|
||||||
|
- `plg_webservices_mokowaas` (Webservices Plugin)
|
||||||
|
|
||||||
|
## Method 2: Install from URL
|
||||||
|
|
||||||
|
1. In Joomla admin, navigate to **System > Install > Extensions**.
|
||||||
|
2. On the **Install from URL** tab, enter the direct download URL for the package ZIP, e.g.:
|
||||||
|
```
|
||||||
|
https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/releases/download/stable/pkg_mokowaas-latest.zip
|
||||||
|
```
|
||||||
|
3. Click **Install**.
|
||||||
|
4. Verify the success message.
|
||||||
|
|
||||||
|
## Post-Installation Verification
|
||||||
|
|
||||||
|
After installation, verify the following:
|
||||||
|
|
||||||
|
1. **Plugin enabled**: Navigate to **System > Plugins** and confirm "System - MokoWaaS" is enabled (it is auto-enabled during installation).
|
||||||
|
2. **Health token generated**: Open the plugin configuration and check the **Diagnostics** tab. The `health_api_token` field should contain an auto-generated token.
|
||||||
|
3. **Branding applied**: The admin login page and dashboard should reflect MokoWaaS branding (logo, colors, footer text).
|
||||||
|
4. **Health endpoint**: Test the health endpoint:
|
||||||
|
```
|
||||||
|
curl -sk -H "Authorization: Bearer <token>" "https://yoursite.com/?mokowaas=health"
|
||||||
|
```
|
||||||
|
5. **Grafana heartbeat**: Check the admin message queue for a Grafana heartbeat confirmation message.
|
||||||
|
|
||||||
|
## What the Installer Does
|
||||||
|
|
||||||
|
During `postflight`, the installer script performs these operations:
|
||||||
|
|
||||||
|
| Step | Description |
|
||||||
|
|---|---|
|
||||||
|
| Enable and protect plugin | Sets `enabled=1`, `protected=1`, `locked=0` in `#__extensions` |
|
||||||
|
| Install MokoOnyx template | Installs the bundled MokoOnyx site template from the plugin payload, sets it as default |
|
||||||
|
| Language overrides | Deploys language override files for en-GB and en-US |
|
||||||
|
| Login support URLs | Updates `mod_loginsupport` to point to Moko Consulting support/docs/news URLs |
|
||||||
|
| Atum branding | Applies brand colors to the Atum admin template |
|
||||||
|
| Action log registration | Registers MokoWaaS in the Joomla action log system |
|
||||||
|
| Health token provisioning | Generates a random API token if one does not exist |
|
||||||
|
| Heartbeat | Sends a registration heartbeat to the Grafana monitoring receiver |
|
||||||
|
|
||||||
|
## Automatic Updates
|
||||||
|
|
||||||
|
MokoWaaS includes an update server configuration that enables automatic update notifications through Joomla's built-in update system.
|
||||||
|
|
||||||
|
The update server URL is:
|
||||||
|
```
|
||||||
|
https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/raw/branch/main/updates.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
When a new version is available:
|
||||||
|
|
||||||
|
1. Joomla's update checker detects the new version from `updates.xml`.
|
||||||
|
2. A notification appears in the admin dashboard.
|
||||||
|
3. Navigate to **System > Update > Extensions** to install the update.
|
||||||
|
4. The `postflight` script runs again, re-applying all configuration steps.
|
||||||
|
|
||||||
|
## Upgrading from Standalone Plugin to Package
|
||||||
|
|
||||||
|
If you previously installed the standalone `plg_system_mokowaas` plugin (before it was packaged as `pkg_mokowaas`), the package installer handles migration automatically:
|
||||||
|
|
||||||
|
1. Install the `pkg_mokowaas.zip` package using either method above.
|
||||||
|
2. The package installer detects the existing standalone plugin and upgrades it in place.
|
||||||
|
3. The additional extensions (`com_mokowaas`, `plg_webservices_mokowaas`) are installed alongside.
|
||||||
|
4. All existing plugin settings are preserved.
|
||||||
|
5. The `protected` flag is set on all package extensions.
|
||||||
|
|
||||||
|
No manual cleanup of the old standalone plugin is required.
|
||||||
|
|
||||||
|
## Uninstallation
|
||||||
|
|
||||||
|
Uninstallation is restricted to the master user. See [Plugin Protection](Plugin-Protection) for details.
|
||||||
|
|
||||||
|
When the master user uninstalls via the Extension Manager:
|
||||||
|
|
||||||
|
1. Language override files are removed from Joomla's global override directories.
|
||||||
|
2. Action log registration is cleaned up.
|
||||||
|
3. An uninstall notification is sent to the monitoring system.
|
||||||
|
4. The package and all sub-extensions are removed.
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# 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
|
||||||
|
```
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# Site Aliases
|
||||||
|
|
||||||
|
MokoWaaS supports multi-domain configurations through the Site Aliases system. This allows a single Joomla installation to respond to multiple domain names, each with independent settings for offline mode, robots directives, and backend access.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Site aliases are configured in the plugin settings under the **Site Aliases** tab.
|
||||||
|
|
||||||
|
### Primary Domain
|
||||||
|
|
||||||
|
Set `primary_domain` to the canonical domain for the site (e.g. `waas.dev.mokoconsulting.tech`). This is the domain that:
|
||||||
|
|
||||||
|
- Serves as the canonical URL for SEO purposes
|
||||||
|
- Hosts the admin backend (when `redirect_backend` is enabled on aliases)
|
||||||
|
- Is used in heartbeat registration with Grafana
|
||||||
|
|
||||||
|
### Alias Entries
|
||||||
|
|
||||||
|
Add alias domains using the repeatable subform table. Each alias entry has the following options:
|
||||||
|
|
||||||
|
| Field | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `domain` | Text | (required) | The alias domain name, e.g. `www.example.com` |
|
||||||
|
| `offline` | Yes/No | No | When Yes, visitors to this alias see the offline page |
|
||||||
|
| `offline_message` | Textarea | -- | Custom message displayed when the alias is offline (only shown when `offline` is Yes) |
|
||||||
|
| `robots` | List | `index, follow` | Robots meta tag directive for this alias |
|
||||||
|
| `redirect_backend` | Yes/No | Yes | When Yes, admin URLs (`/administrator`) on this alias redirect to the primary domain |
|
||||||
|
|
||||||
|
### Robots Options
|
||||||
|
|
||||||
|
Each alias can have its own robots directive:
|
||||||
|
|
||||||
|
| Value | Effect |
|
||||||
|
|---|---|
|
||||||
|
| `index, follow` | Normal indexing (default) |
|
||||||
|
| `noindex, follow` | Do not index pages, but follow links |
|
||||||
|
| `index, nofollow` | Index pages, do not follow links |
|
||||||
|
| `noindex, nofollow` | Do not index or follow |
|
||||||
|
| `none` | Equivalent to `noindex, nofollow` |
|
||||||
|
|
||||||
|
## How Canonical URLs Work
|
||||||
|
|
||||||
|
When a request arrives on an alias domain, MokoWaaS:
|
||||||
|
|
||||||
|
1. Matches the `HTTP_HOST` against configured alias domains
|
||||||
|
2. Applies the alias-specific robots meta tag
|
||||||
|
3. If the alias is marked offline, renders the offline page with the custom message
|
||||||
|
4. If `redirect_backend` is enabled and the request is for `/administrator`, issues a 301 redirect to the primary domain's admin
|
||||||
|
5. Sets the canonical URL to the primary domain equivalent of the current page
|
||||||
|
|
||||||
|
This prevents duplicate content issues when the same site is accessible from multiple domains.
|
||||||
|
|
||||||
|
## Grafana Monitoring for Aliases
|
||||||
|
|
||||||
|
When the plugin sends a heartbeat to the Grafana monitoring receiver, it registers both the primary domain and all alias domains. The monitoring dashboard can then track health status for each domain independently.
|
||||||
|
|
||||||
|
Each alias appears as a separate entry in the Grafana Infinity datasource, pointing to the same health endpoint but accessed via the alias domain. This ensures SSL certificate checks and DNS resolution are validated per-domain.
|
||||||
|
|
||||||
|
## DreamHost Mirror Setup
|
||||||
|
|
||||||
|
For sites hosted on DreamHost, alias domains are typically configured as "mirror" domains in the DreamHost panel:
|
||||||
|
|
||||||
|
1. In DreamHost panel, add the alias domain as a **Mirror** of the primary domain
|
||||||
|
2. Ensure DNS for the alias domain points to the DreamHost server
|
||||||
|
3. Add the alias domain to the MokoWaaS Site Aliases configuration
|
||||||
|
4. Set `redirect_backend` to Yes (recommended) so admin access always uses the primary domain
|
||||||
|
5. Set `robots` to `noindex, nofollow` if the alias is a staging or preview domain
|
||||||
|
|
||||||
|
DreamHost mirrors serve the same filesystem, so no additional Joomla configuration is needed beyond the MokoWaaS alias entry.
|
||||||
Reference in New Issue
Block a user