diff --git a/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php b/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php
index 5737b757..f6c64133 100644
--- a/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php
+++ b/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php
@@ -807,7 +807,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
return $strings;
}
-
/**
* Event triggered after an extension's config is saved.
*
@@ -935,48 +934,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
}
}
- /**
- * Reset all article hit counters to zero.
- *
- * @return int Number of rows affected
- *
- * @since 02.01.08
- */
- protected function resetAllHits()
- {
- $db = Factory::getDbo();
-
- $db->setQuery(
- $db->getQuery(true)
- ->update($db->quoteName('#__content'))
- ->set($db->quoteName('hits') . ' = 0')
- ->where($db->quoteName('hits') . ' > 0')
- );
- $db->execute();
-
- return $db->getAffectedRows();
- }
-
- /**
- * Delete all content version history records.
- *
- * @return int Number of rows deleted
- *
- * @since 02.01.08
- */
- protected function deleteAllVersions()
- {
- $db = Factory::getDbo();
-
- $db->setQuery(
- $db->getQuery(true)
- ->delete($db->quoteName('#__history'))
- );
- $db->execute();
-
- return $db->getAffectedRows();
- }
-
/**
* Event triggered after the route has been determined.
*
@@ -1513,7 +1470,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
// onPreprocessMenuItems — REMOVED, now in plg_system_mokowaas_tenant
// onUserBeforeSave — REMOVED, now in plg_system_mokowaas_firewall
-
// ------------------------------------------------------------------
// Diagnostics / Health Endpoint (called from onAfterInitialise)
// ------------------------------------------------------------------
@@ -4279,130 +4235,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
// License key check (called from onAfterRoute)
// ------------------------------------------------------------------
- /**
- * Show a persistent admin warning if no license key is set on the
- * MokoWaaS update site.
- *
- * Checks the extra_query column in #__update_sites for a dlid value.
- * Also validates the key against MokoGitea on a heartbeat interval
- * (once per day) and warns if the key is invalid or expired.
- *
- * @return void
- *
- * @since 02.31.00
- */
- protected function warnMissingLicenseKey(): void
- {
- // Only show to master users
- if (!$this->isMasterUser())
- {
- return;
- }
-
- // Only warn once per session
- $session = Factory::getSession();
-
- if ($session->get('mokowaas.license_warned', false))
- {
- return;
- }
-
- $session->set('mokowaas.license_warned', true);
-
- try
- {
- $db = Factory::getDbo();
-
- $query = $db->getQuery(true)
- ->select($db->quoteName('extra_query'))
- ->from($db->quoteName('#__update_sites'))
- ->where('(' . $db->quoteName('name') . ' LIKE ' . $db->quote('%MokoWaaS%')
- . ' OR ' . $db->quoteName('location') . ' LIKE ' . $db->quote('%MokoWaaS%') . ')')
- ->setLimit(1);
- $db->setQuery($query);
- $extraQuery = (string) $db->loadResult();
-
- if (empty($extraQuery) || strpos($extraQuery, 'dlid=') === false)
- {
- $this->app->enqueueMessage(
- 'Moko Consulting License Key Required — '
- . 'No download key is configured. Updates will not be available until a valid license key is entered. '
- . 'Go to System → Update Sites '
- . 'and enter your license key in the Download Key field for the MokoWaaS update site.',
- 'warning'
- );
-
- return;
- }
-
- // Extract the key value from extra_query
- parse_str($extraQuery, $parsed);
- $licenseKey = $parsed['dlid'] ?? '';
-
- if (empty($licenseKey))
- {
- return;
- }
-
- // Heartbeat validation — check once per day
- $session = Factory::getSession();
- $lastCheck = (int) $session->get('mokowaas.license_check', 0);
- $now = time();
-
- if (($now - $lastCheck) < 86400)
- {
- // Show cached warning if key was invalid last check
- if ($session->get('mokowaas.license_invalid', false))
- {
- $this->app->enqueueMessage(
- 'Moko Consulting License Key Invalid — '
- . 'Your license key could not be validated. Please verify your key in '
- . 'System → Update Sites.',
- 'error'
- );
- }
-
- return;
- }
-
- // Validate against MokoGitea
- $session->set('mokowaas.license_check', $now);
-
- $validateUrl = 'https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS/updates.xml'
- . '?dlid=' . urlencode($licenseKey)
- . '&domain=' . urlencode(Uri::root());
-
- $ch = curl_init($validateUrl);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_TIMEOUT, 10);
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- $response = curl_exec($ch);
- $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
- curl_close($ch);
-
- // Empty or non-200 means invalid key
- $isValid = ($httpCode === 200 && $response && strpos($response, '') !== false);
-
- $session->set('mokowaas.license_invalid', !$isValid);
-
- if (!$isValid)
- {
- $this->app->enqueueMessage(
- 'Moko Consulting License Key Invalid — '
- . 'Your license key could not be validated. Updates will not be available. '
- . 'Please verify your key in '
- . 'System → Update Sites.',
- 'error'
- );
- }
- }
- catch (\Throwable $e)
- {
- // Silent — license check is non-critical
- }
- }
-
// ------------------------------------------------------------------
/**
@@ -4538,110 +4370,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
*
* @since 02.01.08
*/
- /**
- * Enforce development mode settings.
- *
- * When dev mode is ON:
- * - Disable Joomla caching
- * - Enable Joomla debug mode (Global Config)
- * - Enable MokoOnyx template debug
- * - Disable article hit recording
- *
- * When dev mode is OFF (and was previously on):
- * - Reset all content version history
- * - Reset article published dates to now
- *
- * @return void
- *
- * @since 02.01.15
- */
- protected function enforceDevMode()
- {
- if (!$this->params->get('dev_mode', 0))
- {
- return;
- }
-
- // Disable caching
- $config = Factory::getConfig();
- $config->set('caching', 0);
-
- // Enable Joomla debug
- $config->set('debug', 1);
-
- // Enable MokoOnyx template debug
- $this->setTemplateParam('mokoonyx', 'debug', 1);
-
- // Show offline page on primary domain only — site aliases
- // and dev.* subdomains bypass offline mode for development
- $currentHost = $_SERVER['HTTP_HOST'] ?? '';
- $primaryDomain = $this->params->get('primary_domain', '');
-
- if (!empty($primaryDomain) && $currentHost === $primaryDomain)
- {
- $config->set('offline', 1);
- }
-
- // Suppress hit recording
- try
- {
- $db = Factory::getDbo();
- $db->setQuery(
- $db->getQuery(true)
- ->update($db->quoteName('#__content'))
- ->set($db->quoteName('hits') . ' = 0')
- ->where($db->quoteName('hits') . ' > 0')
- )->execute();
- }
- catch (\Throwable $e)
- {
- // Silent
- }
- }
-
- /**
- * Actions to run when dev mode is turned off.
- *
- * Resets content versions and hits, disables debug.
- *
- * @return void
- *
- * @since 02.31.00
- */
- protected function onDevModeDisabled(): void
- {
- try
- {
- $db = Factory::getDbo();
-
- // Delete all content version history
- $db->setQuery(
- $db->getQuery(true)->delete($db->quoteName('#__history'))
- )->execute();
-
- // Reset hits
- $db->setQuery(
- $db->getQuery(true)
- ->update($db->quoteName('#__content'))
- ->set($db->quoteName('hits') . ' = 0')
- )->execute();
-
- // Disable debug
- $this->setTemplateParam('mokoonyx', 'debug', 0);
-
- // Take site back online
- Factory::getConfig()->set('offline', 0);
-
- $this->app->enqueueMessage(
- 'Development mode disabled — versions cleared, hits reset, debug off, site online.',
- 'message'
- );
- }
- catch (\Throwable $e)
- {
- Log::add('Dev mode cleanup failed: ' . $e->getMessage(), Log::WARNING, 'mokowaas');
- }
- }
/**
* Set a parameter on a template style.
@@ -4689,194 +4417,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
}
}
- protected function enforceHttps()
- {
- if (!$this->params->get('force_https', 0))
- {
- return;
- }
-
- if ($this->app->isClient('cli'))
- {
- return;
- }
-
- $isHttps = (!empty($_SERVER['HTTPS'])
- && $_SERVER['HTTPS'] !== 'off')
- || ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https';
-
- if (!$isHttps)
- {
- $this->app->redirect(
- 'https://' . $_SERVER['HTTP_HOST']
- . $_SERVER['REQUEST_URI'], 301
- );
- }
- }
-
- /**
- * Enforce admin session idle timeout.
- *
- * @return void
- *
- * @since 02.01.08
- */
- protected function enforceAdminSessionTimeout()
- {
- $timeout = (int) $this->params->get('admin_session_timeout', 0);
-
- if ($timeout <= 0)
- {
- return;
- }
-
- // Don't timeout the master user
- if ($this->isMasterUser())
- {
- return;
- }
-
- // Trusted IPs — session lifetime already extended in boot()
- if ($this->ipIsTrusted())
- {
- return;
- }
-
- $session = Factory::getSession();
- $lastHit = $session->get('mokowaas.last_activity', 0);
- $now = time();
-
- if ($lastHit > 0 && ($now - $lastHit) > ($timeout * 60))
- {
- $this->app->logout();
- $this->app->redirect(
- Route::_('index.php', false)
- );
-
- return;
- }
-
- $session->set('mokowaas.last_activity', $now);
- }
-
- /**
- * Check whether the current request IP matches any trusted IP entry.
- *
- * Supports exact IPs, CIDR notation (e.g. 10.0.0.0/8), and
- * wildcard patterns (e.g. 192.168.1.*).
- *
- * @return bool True if the current IP is in the trusted list.
- *
- * @since 02.11.00
- */
- protected function ipIsTrusted(): bool
- {
- $entries = $this->params->get('trusted_ips', '');
-
- if (empty($entries))
- {
- return false;
- }
-
- // Subform stores as JSON string or array
- if (\is_string($entries))
- {
- $entries = json_decode($entries, true);
- }
-
- if (!\is_array($entries))
- {
- return false;
- }
-
- $ip = $this->app
- ? $this->app->input->server->getString('REMOTE_ADDR', '')
- : ($_SERVER['REMOTE_ADDR'] ?? '');
- $ipLong = ip2long($ip);
-
- if ($ipLong === false)
- {
- return false;
- }
-
- foreach ($entries as $entry)
- {
- if (empty($entry['enabled']) || empty($entry['ip']))
- {
- continue;
- }
-
- $range = trim($entry['ip']);
-
- // Wildcard: 192.168.1.*
- if (str_contains($range, '*'))
- {
- $pattern = '/^' . str_replace(['.', '*'], ['\\.', '\\d+'], $range) . '$/';
-
- if (preg_match($pattern, $ip))
- {
- return true;
- }
-
- continue;
- }
-
- // CIDR: 10.0.0.0/8
- if (str_contains($range, '/'))
- {
- [$subnet, $bits] = explode('/', $range, 2);
- $subnetLong = ip2long($subnet);
- $mask = -1 << (32 - (int) $bits);
-
- if ($subnetLong !== false && ($ipLong & $mask) === ($subnetLong & $mask))
- {
- return true;
- }
-
- continue;
- }
-
- // Exact match
- if ($ip === $range)
- {
- return true;
- }
- }
-
- return false;
- }
-
-
- /**
- * Override Joomla upload restrictions at runtime.
- *
- * @return void
- *
- * @since 02.01.08
- */
- protected function enforceUploadRestrictions()
- {
- $types = $this->params->get('upload_allowed_types', '');
- $maxMb = (int) $this->params->get('upload_max_size_mb', 0);
-
- if (empty($types) && $maxMb <= 0)
- {
- return;
- }
-
- $config = $this->app->getConfig();
-
- if (!empty($types))
- {
- $config->set('upload_extensions', $types);
- }
-
- if ($maxMb > 0)
- {
- $config->set('upload_maxsize', $maxMb);
- }
- }
-
/**
* Enforce login support module URLs on admin requests.
*
@@ -4945,121 +4485,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
// Tenant Restrictions (called from onAfterRoute)
// ------------------------------------------------------------------
- /**
- * Check admin routes against restriction rules and redirect if blocked.
- *
- * @return void
- *
- * @since 02.01.08
- */
- protected function enforceAdminRestrictions()
- {
- // Master user bypasses ALL restrictions
- if ($this->isMasterUser())
- {
- return;
- }
-
- $input = $this->app->input;
- $option = $input->get('option', '');
- $view = $input->get('view', '');
- $task = $input->get('task', '');
-
- // Disable install-from-URL for non-master users
- if ($this->params->get('disable_install_url', 1)
- && $option === 'com_installer'
- && stripos($task, 'install') !== false
- && $input->get('installtype') === 'url')
- {
- $this->blockAccess('Install from URL is disabled.');
-
- return;
- }
-
- $blocked = [];
-
- if ($this->params->get('restrict_installer', 1))
- {
- // Allow the update view by default so tenants can update extensions
- $allowUpdates = (int) $this->params->get('allow_extension_updates', 1);
-
- if ($allowUpdates && $option === 'com_installer'
- && \in_array($view, ['update', 'updatesites'], true))
- {
- // Do not block — update views are permitted
- }
- elseif ($option === 'com_installer')
- {
- $this->blockAccess('Access restricted.');
-
- return;
- }
- }
-
- if ($this->params->get('hide_sysinfo', 1))
- {
- $blocked[] = [
- 'option' => 'com_admin',
- 'view' => 'sysinfo',
- ];
- }
-
- if ($this->params->get('restrict_global_config', 1))
- {
- $blocked[] = [
- 'option' => 'com_config',
- 'view' => 'application',
- ];
- // Also block empty view (default landing = global config)
- if ($option === 'com_config' && $view === '')
- {
- $this->blockAccess('Access restricted.');
-
- return;
- }
- }
-
- if ($this->params->get('restrict_template_editing', 1))
- {
- $blocked[] = [
- 'option' => 'com_templates',
- 'view' => 'template',
- ];
- }
-
- foreach ($blocked as $rule)
- {
- if ($option !== $rule['option'])
- {
- continue;
- }
-
- if (isset($rule['view']) && $view !== $rule['view'])
- {
- continue;
- }
-
- $this->blockAccess('Access restricted.');
-
- return;
- }
- }
-
- /**
- * Redirect to admin dashboard with an error message.
- *
- * @param string $message Error message to display
- *
- * @return void
- *
- * @since 02.01.08
- */
- protected function blockAccess($message)
- {
- $this->app->enqueueMessage($message, 'error');
- $this->app->redirect(Route::_('index.php', false));
- }
-
/**
* Check whether the current user is the master WaaS user.
*
@@ -5111,38 +4536,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
return $this->masterNames;
}
- /**
- * Build the list of components to hide from admin menu.
- *
- * Combines explicit hidden_menu_items config with components that
- * are implicitly blocked by other restriction toggles.
- *
- * @return array Component option strings
- *
- * @since 02.01.08
- */
- protected function getHiddenMenuComponents()
- {
- $hidden = array_filter(array_map(
- 'trim',
- explode("\n", $this->params->get('hidden_menu_items', ''))
- ));
-
- // Auto-hide components that are restricted (keep visible when updates are allowed)
- if ($this->params->get('restrict_installer', 1)
- && !$this->params->get('allow_extension_updates', 1))
- {
- $hidden[] = 'com_installer';
- }
-
- if ($this->params->get('hide_sysinfo', 1))
- {
- $hidden[] = 'com_admin';
- }
-
- return array_unique($hidden);
- }
-
// ------------------------------------------------------------------
// Atum Template Branding (called from onAfterInitialise)
// ------------------------------------------------------------------