wasImported('admintools')) { return null; } $db = $this->getDatabase(); try { $result = (object) [ 'component' => false, 'waf_config' => false, 'storage' => false, 'ip_blocks' => 0, ]; // Check component $db->setQuery("SELECT COUNT(*) FROM #__extensions WHERE element = 'com_admintools' AND type = 'component'"); $result->component = (int) $db->loadResult() > 0; // Check WAF config table $db->setQuery('SHOW TABLES LIKE ' . $db->quote('%admintools_wafconfig%')); if ($db->loadResult()) { $result->waf_config = true; $db->setQuery('SELECT COUNT(*) FROM #__admintools_wafconfig'); $result->waf_settings = (int) $db->loadResult(); } // Check storage table $db->setQuery('SHOW TABLES LIKE ' . $db->quote('%admintools_storage%')); if ($db->loadResult()) { $result->storage = true; } // Check IP blocklist $db->setQuery('SHOW TABLES LIKE ' . $db->quote('%admintools_ipblock%')); if ($db->loadResult()) { $db->setQuery('SELECT COUNT(*) FROM #__admintools_ipblock'); $result->ip_blocks = (int) $db->loadResult(); } // Only available if at least one data source exists if (!$result->component && !$result->waf_config && !$result->storage) { return null; } return $result; } catch (\Throwable $e) { return null; } } /** * Import Admin Tools settings into MokoSuite. */ public function importAdminTools(): array { $db = $this->getDatabase(); $results = ['firewall' => 0, 'htaccess' => 0, 'ip_blocks' => 0, 'disabled' => false]; try { // ============================================================ // 1. Import WAF Config → Firewall plugin params // ============================================================ $wafSettings = $this->readWafConfig($db); $firewallParams = $this->mapWafToFirewall($wafSettings); if (!empty($firewallParams)) { $this->mergePluginParams('mokosuite_firewall', 'system', $firewallParams); $results['firewall'] = \count($firewallParams); } // ============================================================ // 2. Import htaccess settings → component htaccess options // ============================================================ $htaccessSettings = $this->readHtaccessConfig($db); $htaccessOptions = $this->mapToHtaccess($htaccessSettings, $wafSettings); if (!empty($htaccessOptions)) { $this->mergeComponentHtaccessOptions($htaccessOptions); $results['htaccess'] = \count($htaccessOptions); } // ============================================================ // 3. Import IP blocklist → Firewall IP deny list // ============================================================ $ipBlocks = $this->readIpBlocklist($db); if (!empty($ipBlocks)) { $this->mergeIpBlocklist($ipBlocks); $results['ip_blocks'] = \count($ipBlocks); } // ============================================================ // 4. Disable Admin Tools // ============================================================ $this->disableAdminTools($db); $results['disabled'] = true; $this->markImported('admintools'); return [ 'success' => true, 'message' => \sprintf( 'Imported %d firewall settings, %d htaccess options, %d blocked IPs from Admin Tools. Admin Tools has been disabled.', $results['firewall'], $results['htaccess'], $results['ip_blocks'] ), 'counts' => $results, ]; } catch (\Throwable $e) { return ['success' => false, 'message' => 'Import failed: ' . $e->getMessage()]; } } /** * Read WAF config from #__admintools_wafconfig. */ private function readWafConfig($db): array { try { $db->setQuery('SHOW TABLES LIKE ' . $db->quote('%admintools_wafconfig%')); if (!$db->loadResult()) { return []; } $db->setQuery('SELECT * FROM #__admintools_wafconfig'); $rows = $db->loadObjectList() ?: []; $config = []; foreach ($rows as $row) { $key = $row->key ?? $row->option ?? ''; if (!empty($key)) { $config[$key] = $row->value ?? ''; } } return $config; } catch (\Throwable $e) { return []; } } /** * Read htaccess/server config from #__admintools_storage. */ private function readHtaccessConfig($db): array { try { $db->setQuery('SHOW TABLES LIKE ' . $db->quote('%admintools_storage%')); if (!$db->loadResult()) { return []; } $db->setQuery('SELECT * FROM #__admintools_storage'); $rows = $db->loadObjectList() ?: []; $config = []; foreach ($rows as $row) { $key = $row->key ?? ''; if (!empty($key)) { $config[$key] = $row->value ?? ''; } } return $config; } catch (\Throwable $e) { return []; } } /** * Read IP blocklist from #__admintools_ipblock. */ private function readIpBlocklist($db): array { try { $db->setQuery('SHOW TABLES LIKE ' . $db->quote('%admintools_ipblock%')); if (!$db->loadResult()) { return []; } $db->setQuery('SELECT ip FROM #__admintools_ipblock'); return $db->loadColumn() ?: []; } catch (\Throwable $e) { return []; } } /** * Map Admin Tools WAF config to MokoSuite firewall plugin params. */ private function mapWafToFirewall(array $waf): array { $params = []; // WAF shields if (isset($waf['sqlishield'])) { $params['waf_sqli'] = (int) $waf['sqlishield'] ? 1 : 0; } if (isset($waf['antispam'])) { $params['waf_xss'] = (int) $waf['antispam'] ? 1 : 0; } if (isset($waf['muashield'])) { $params['waf_mua'] = (int) $waf['muashield'] ? 1 : 0; } if (isset($waf['rfishield'])) { $params['waf_rfi'] = (int) $waf['rfishield'] ? 1 : 0; } if (isset($waf['dfishield'])) { $params['waf_dfi'] = (int) $waf['dfishield'] ? 1 : 0; } if (isset($waf['uploadshield'])) { // Map to our block_direct_php $params['block_direct_php'] = (int) $waf['uploadshield'] ? 1 : 0; } // Admin secret URL if (!empty($waf['adminpw'])) { $params['admin_secret'] = $waf['adminpw']; } // Block frontend super user login if (isset($waf['nofesalogin'])) { $params['block_frontend_superuser'] = (int) $waf['nofesalogin'] ? 1 : 0; } // Session timeout if (!empty($waf['sessionshield']) && !empty($waf['session_timeout'])) { $params['admin_session_timeout'] = (int) $waf['session_timeout']; } // Template switch blocking if (isset($waf['tmpl'])) { $params['block_template_switch'] = (int) $waf['tmpl'] ? 1 : 0; } // Blocked sensitive files if (isset($waf['hogfiles'])) { $params['block_sensitive_files'] = (int) $waf['hogfiles'] ? 1 : 0; } return $params; } /** * Map Admin Tools config to MokoSuite htaccess maker options. */ private function mapToHtaccess(array $storage, array $waf): array { $opts = []; // Server signature if (isset($waf['serversignature']) || isset($storage['serversignature'])) { $opts['disable_server_signature'] = 1; } // Clickjacking if (isset($waf['clickjacking']) || isset($storage['xframeoptions'])) { $opts['prevent_clickjacking'] = 1; } // HSTS if (!empty($storage['hstsheader']) || !empty($waf['hstsheader'])) { $opts['hsts_enabled'] = 1; if (!empty($storage['hstsmaxage'])) { $opts['hsts_max_age'] = (int) $storage['hstsmaxage']; } } // GZip if (isset($storage['gzipcompression'])) { $opts['enable_gzip'] = (int) $storage['gzipcompression'] ? 1 : 0; } // Expiration if (isset($storage['exptime'])) { $opts['enable_expires'] = (int) $storage['exptime'] ? 1 : 0; } // ETag if (isset($storage['etagtype'])) { $opts['etag_control'] = ($storage['etagtype'] === 'none') ? 1 : 0; } // Redirect www / non-www if (!empty($storage['wwwredir'])) { $map = ['www' => 'www', 'nowww' => 'non-www']; $opts['www_redirect'] = $map[$storage['wwwredir']] ?? 'off'; } // Directory listing if (isset($storage['nodirlisting'])) { $opts['disable_directory_listing'] = (int) $storage['nodirlisting'] ? 1 : 0; } // Block PHP in uploads if (isset($storage['phpuploadexec'])) { $opts['block_php_in_uploads'] = (int) $storage['phpuploadexec'] ? 1 : 0; } // Sensitive files if (isset($storage['hogfiles'])) { $opts['block_sensitive_files'] = (int) $storage['hogfiles'] ? 1 : 0; } return $opts; } /** * Merge params into a plugin's existing params. */ private function mergePluginParams(string $element, string $folder, array $newParams): void { $db = $this->getDatabase(); $query = $db->getQuery(true) ->select($db->quoteName('params')) ->from($db->quoteName('#__extensions')) ->where($db->quoteName('element') . ' = ' . $db->quote($element)) ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) ->where($db->quoteName('folder') . ' = ' . $db->quote($folder)); $db->setQuery($query); $current = new Registry($db->loadResult() ?? '{}'); foreach ($newParams as $key => $value) { $current->set($key, $value); } $db->setQuery( $db->getQuery(true) ->update($db->quoteName('#__extensions')) ->set($db->quoteName('params') . ' = ' . $db->quote($current->toString())) ->where($db->quoteName('element') . ' = ' . $db->quote($element)) ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) ->where($db->quoteName('folder') . ' = ' . $db->quote($folder)) )->execute(); } /** * Merge htaccess options into the component params. */ private function mergeComponentHtaccessOptions(array $options): void { $db = $this->getDatabase(); $query = $db->getQuery(true) ->select($db->quoteName('params')) ->from($db->quoteName('#__extensions')) ->where($db->quoteName('element') . ' = ' . $db->quote('com_mokosuite')) ->where($db->quoteName('type') . ' = ' . $db->quote('component')); $db->setQuery($query); $params = new Registry($db->loadResult() ?? '{}'); $htaccess = (array) json_decode(json_encode($params->get('htaccess', new \stdClass())), true); foreach ($options as $key => $value) { $htaccess[$key] = $value; } $params->set('htaccess', $htaccess); $db->setQuery( $db->getQuery(true) ->update($db->quoteName('#__extensions')) ->set($db->quoteName('params') . ' = ' . $db->quote($params->toString())) ->where($db->quoteName('element') . ' = ' . $db->quote('com_mokosuite')) ->where($db->quoteName('type') . ' = ' . $db->quote('component')) )->execute(); } /** * Merge imported IPs into the firewall IP blocklist. */ private function mergeIpBlocklist(array $ips): void { $db = $this->getDatabase(); $query = $db->getQuery(true) ->select($db->quoteName('params')) ->from($db->quoteName('#__extensions')) ->where($db->quoteName('element') . ' = ' . $db->quote('mokosuite_firewall')) ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) ->where($db->quoteName('folder') . ' = ' . $db->quote('system')); $db->setQuery($query); $params = new Registry($db->loadResult() ?? '{}'); $blocklist = json_decode($params->get('ip_blocklist', '[]'), true) ?: []; $existingIps = array_column($blocklist, 'ip'); foreach ($ips as $ip) { $ip = trim($ip); if (empty($ip) || \in_array($ip, $existingIps, true)) { continue; } $blocklist[] = [ 'ip' => $ip, 'enabled' => '1', 'label' => 'Imported from Admin Tools', ]; } $params->set('ip_blocklist', json_encode($blocklist)); $db->setQuery( $db->getQuery(true) ->update($db->quoteName('#__extensions')) ->set($db->quoteName('params') . ' = ' . $db->quote($params->toString())) ->where($db->quoteName('element') . ' = ' . $db->quote('mokosuite_firewall')) ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) ->where($db->quoteName('folder') . ' = ' . $db->quote('system')) )->execute(); } /** * Disable Admin Tools component and plugins. */ private function disableAdminTools($db): void { // Disable component $db->setQuery( $db->getQuery(true) ->update($db->quoteName('#__extensions')) ->set($db->quoteName('enabled') . ' = 0') ->where($db->quoteName('element') . ' = ' . $db->quote('com_admintools')) )->execute(); // Disable all Admin Tools plugins $db->setQuery( $db->getQuery(true) ->update($db->quoteName('#__extensions')) ->set($db->quoteName('enabled') . ' = 0') ->where($db->quoteName('element') . ' LIKE ' . $db->quote('admintools%')) ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) )->execute(); Log::add('Admin Tools component and plugins disabled after MokoSuite import', Log::INFO, 'mokosuite'); } // ================================================================== // Akeeba Ticket System Import // ================================================================== /** * Check if ATS tables exist. * Returns null if already imported or no data found. */ public function checkAtsAvailable(): ?object { if ($this->wasImported('ats')) { return null; } $db = $this->getDatabase(); try { $db->setQuery('SHOW TABLES LIKE ' . $db->quote('%ats_tickets%')); if (!$db->loadResult()) { return null; } $db->setQuery('SELECT COUNT(*) FROM #__ats_tickets'); $tickets = (int) $db->loadResult(); $db->setQuery('SELECT COUNT(*) FROM #__ats_posts'); $posts = (int) $db->loadResult(); return (object) ['tickets' => $tickets, 'posts' => $posts]; } catch (\Throwable $e) { return null; } } /** * Import from Akeeba Ticket System and disable it. */ public function importAts(): array { // Delegate to TicketsModel for the actual import $ticketsModel = new TicketsModel(); $result = $ticketsModel->importFromAts(); if (!$result['success']) { return $result; } // Disable ATS after successful import try { $db = $this->getDatabase(); $db->setQuery( $db->getQuery(true) ->update($db->quoteName('#__extensions')) ->set($db->quoteName('enabled') . ' = 0') ->where($db->quoteName('element') . ' = ' . $db->quote('com_ats')) )->execute(); $db->setQuery( $db->getQuery(true) ->update($db->quoteName('#__extensions')) ->set($db->quoteName('enabled') . ' = 0') ->where($db->quoteName('element') . ' LIKE ' . $db->quote('ats%')) ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) )->execute(); $result['message'] .= ' Akeeba Ticket System has been disabled.'; Log::add('Akeeba Ticket System disabled after MokoSuite import', Log::INFO, 'mokosuite'); } catch (\Throwable $e) { $result['message'] .= ' Warning: could not disable ATS: ' . $e->getMessage(); } $this->markImported('ats'); return $result; } // ================================================================== // Import markers (stored in component params) // ================================================================== private function wasImported(string $key): bool { try { $db = $this->getDatabase(); $db->setQuery( $db->getQuery(true) ->select($db->quoteName('params')) ->from($db->quoteName('#__extensions')) ->where($db->quoteName('element') . ' = ' . $db->quote('com_mokosuite')) ->where($db->quoteName('type') . ' = ' . $db->quote('component')) ); $params = new Registry($db->loadResult() ?? '{}'); return (bool) $params->get('imported_' . $key, false); } catch (\Throwable $e) { return false; } } private function markImported(string $key): void { try { $db = $this->getDatabase(); $db->setQuery( $db->getQuery(true) ->select($db->quoteName('params')) ->from($db->quoteName('#__extensions')) ->where($db->quoteName('element') . ' = ' . $db->quote('com_mokosuite')) ->where($db->quoteName('type') . ' = ' . $db->quote('component')) ); $params = new Registry($db->loadResult() ?? '{}'); $params->set('imported_' . $key, 1); $db->setQuery( $db->getQuery(true) ->update($db->quoteName('#__extensions')) ->set($db->quoteName('params') . ' = ' . $db->quote($params->toString())) ->where($db->quoteName('element') . ' = ' . $db->quote('com_mokosuite')) ->where($db->quoteName('type') . ' = ' . $db->quote('component')) )->execute(); } catch (\Throwable $e) { Log::add('Import marker error: ' . $e->getMessage(), Log::WARNING, 'mokosuite'); } } }