diff --git a/CHANGELOG.md b/CHANGELOG.md index f516082..d949b54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - License/subscription check - System email template branding (DB approach) +### Added +- Trusted IPs: configurable repeatable rows of IP addresses, CIDR ranges, and wildcards that bypass admin session timeout +- Supports exact IPs (192.168.1.100), CIDR (10.0.0.0/24), and wildcards (192.168.1.*) +- Each entry has a label and enabled toggle for easy management + ## [02.06.00] - 2026-05-25 ### Added diff --git a/README.md b/README.md index 8d0d747..2decfd4 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ DEFGROUP: Joomla.Plugin INGROUP: MokoWaaS REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoWaaS - VERSION: 02.10.04 + VERSION: 02.10.05 PATH: /README.md BRIEF: MokoWaaS platform plugin for Joomla --> diff --git a/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php b/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php index 7cd510c..f99ce7b 100644 --- a/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php +++ b/src/packages/plg_system_mokowaas/Extension/MokoWaaS.php @@ -3343,6 +3343,14 @@ class MokoWaaS extends CMSPlugin return; } + // Don't timeout trusted IPs — extend their session instead + if ($this->ipIsTrusted()) + { + ini_set('session.gc_maxlifetime', 315360000); + + return; + } + $session = Factory::getSession(); $lastHit = $session->get('mokowaas.last_activity', 0); $now = time(); @@ -3360,6 +3368,91 @@ class MokoWaaS extends CMSPlugin $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->input->server->getString('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. diff --git a/src/packages/plg_system_mokowaas/forms/trusted_ip_entry.xml b/src/packages/plg_system_mokowaas/forms/trusted_ip_entry.xml new file mode 100644 index 0000000..4e06f39 --- /dev/null +++ b/src/packages/plg_system_mokowaas/forms/trusted_ip_entry.xml @@ -0,0 +1,28 @@ + +
+ + + + + + + diff --git a/src/packages/plg_system_mokowaas/language/en-GB/plg_system_mokowaas.ini b/src/packages/plg_system_mokowaas/language/en-GB/plg_system_mokowaas.ini index aa455c4..538d0cf 100644 --- a/src/packages/plg_system_mokowaas/language/en-GB/plg_system_mokowaas.ini +++ b/src/packages/plg_system_mokowaas/language/en-GB/plg_system_mokowaas.ini @@ -120,6 +120,13 @@ PLG_SYSTEM_MOKOWAAS_FORCE_HTTPS_LABEL="Force HTTPS" PLG_SYSTEM_MOKOWAAS_FORCE_HTTPS_DESC="Redirect all HTTP requests to HTTPS. Supports reverse proxy setups." PLG_SYSTEM_MOKOWAAS_SESSION_TIMEOUT_LABEL="Admin Session Timeout" PLG_SYSTEM_MOKOWAAS_SESSION_TIMEOUT_DESC="Minutes of idle time before admin sessions expire. 0 uses the Joomla default." +PLG_SYSTEM_MOKOWAAS_TRUSTED_IPS_LABEL="Trusted IPs (No Session Timeout)" +PLG_SYSTEM_MOKOWAAS_TRUSTED_IPS_DESC="Sessions from these IP addresses or ranges will never time out. Supports exact IPs, CIDR notation (e.g. 10.0.0.0/24), and wildcards (e.g. 192.168.1.*)." +PLG_SYSTEM_MOKOWAAS_TRUSTED_IP_ADDR_LABEL="IP / CIDR" +PLG_SYSTEM_MOKOWAAS_TRUSTED_IP_ADDR_DESC="An IP address, CIDR range, or wildcard pattern." +PLG_SYSTEM_MOKOWAAS_TRUSTED_IP_LABEL_LABEL="Label" +PLG_SYSTEM_MOKOWAAS_TRUSTED_IP_LABEL_DESC="A descriptive label for this entry (e.g. Office, VPN)." +PLG_SYSTEM_MOKOWAAS_TRUSTED_IP_ENABLED_LABEL="Enabled" PLG_SYSTEM_MOKOWAAS_PASSWORD_LENGTH_LABEL="Minimum Password Length" PLG_SYSTEM_MOKOWAAS_PASSWORD_LENGTH_DESC="Minimum number of characters required for user passwords." PLG_SYSTEM_MOKOWAAS_PASSWORD_UPPER_LABEL="Require Uppercase" diff --git a/src/packages/plg_system_mokowaas/language/en-US/plg_system_mokowaas.ini b/src/packages/plg_system_mokowaas/language/en-US/plg_system_mokowaas.ini index 71d1574..4adb06c 100644 --- a/src/packages/plg_system_mokowaas/language/en-US/plg_system_mokowaas.ini +++ b/src/packages/plg_system_mokowaas/language/en-US/plg_system_mokowaas.ini @@ -120,6 +120,13 @@ PLG_SYSTEM_MOKOWAAS_FORCE_HTTPS_LABEL="Force HTTPS" PLG_SYSTEM_MOKOWAAS_FORCE_HTTPS_DESC="Redirect all HTTP requests to HTTPS. Supports reverse proxy setups." PLG_SYSTEM_MOKOWAAS_SESSION_TIMEOUT_LABEL="Admin Session Timeout" PLG_SYSTEM_MOKOWAAS_SESSION_TIMEOUT_DESC="Minutes of idle time before admin sessions expire. 0 uses the Joomla default." +PLG_SYSTEM_MOKOWAAS_TRUSTED_IPS_LABEL="Trusted IPs (No Session Timeout)" +PLG_SYSTEM_MOKOWAAS_TRUSTED_IPS_DESC="Sessions from these IP addresses or ranges will never time out. Supports exact IPs, CIDR notation (e.g. 10.0.0.0/24), and wildcards (e.g. 192.168.1.*)." +PLG_SYSTEM_MOKOWAAS_TRUSTED_IP_ADDR_LABEL="IP / CIDR" +PLG_SYSTEM_MOKOWAAS_TRUSTED_IP_ADDR_DESC="An IP address, CIDR range, or wildcard pattern." +PLG_SYSTEM_MOKOWAAS_TRUSTED_IP_LABEL_LABEL="Label" +PLG_SYSTEM_MOKOWAAS_TRUSTED_IP_LABEL_DESC="A descriptive label for this entry (e.g. Office, VPN)." +PLG_SYSTEM_MOKOWAAS_TRUSTED_IP_ENABLED_LABEL="Enabled" PLG_SYSTEM_MOKOWAAS_PASSWORD_LENGTH_LABEL="Minimum Password Length" PLG_SYSTEM_MOKOWAAS_PASSWORD_LENGTH_DESC="Minimum number of characters required for user passwords." PLG_SYSTEM_MOKOWAAS_PASSWORD_UPPER_LABEL="Require Uppercase" diff --git a/src/packages/plg_system_mokowaas/mokowaas.xml b/src/packages/plg_system_mokowaas/mokowaas.xml index f887dca..1eb7123 100644 --- a/src/packages/plg_system_mokowaas/mokowaas.xml +++ b/src/packages/plg_system_mokowaas/mokowaas.xml @@ -322,6 +322,17 @@ label="PLG_SYSTEM_MOKOWAAS_SESSION_TIMEOUT_LABEL" description="PLG_SYSTEM_MOKOWAAS_SESSION_TIMEOUT_DESC" default="60" hint="Minutes (0 = Joomla default)" /> +