e2813d0290
Hidden field defaults aren't in database params until plugin is re-saved. Added same manifest XML fallback used for signing_key.
875 lines
25 KiB
PHP
875 lines
25 KiB
PHP
<?php
|
|
/**
|
|
* @package MokoWaaS
|
|
* @subpackage com_mokowaas
|
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
|
* @license GNU General Public License version 3 or later; see LICENSE
|
|
*/
|
|
|
|
namespace Moko\Component\MokoWaaS\Administrator\Controller;
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
use Joomla\CMS\MVC\Controller\BaseController;
|
|
use Joomla\CMS\Factory;
|
|
use Joomla\CMS\Language\Text;
|
|
use Joomla\CMS\Router\Route;
|
|
use Joomla\CMS\Session\Session;
|
|
|
|
class DisplayController extends BaseController
|
|
{
|
|
protected $default_view = 'dashboard';
|
|
|
|
/**
|
|
* ACL map: view name => required permission.
|
|
*/
|
|
private const VIEW_ACL = [
|
|
'dashboard' => 'mokowaas.dashboard',
|
|
'extensions' => 'mokowaas.extensions',
|
|
'htaccess' => 'mokowaas.htaccess',
|
|
'tickets' => 'mokowaas.tickets',
|
|
'ticket' => 'mokowaas.tickets',
|
|
'privacy' => 'core.admin',
|
|
'waflog' => 'core.admin',
|
|
'categories' => 'mokowaas.tickets',
|
|
'canned' => 'mokowaas.tickets',
|
|
'automation' => 'core.admin',
|
|
'database' => 'core.admin',
|
|
'cleanup' => 'mokowaas.cache',
|
|
];
|
|
|
|
public function display($cachable = false, $urlparams = [])
|
|
{
|
|
$view = $this->input->get('view', $this->default_view);
|
|
$acl = self::VIEW_ACL[$view] ?? 'core.manage';
|
|
|
|
if (!$this->checkAcl($acl))
|
|
{
|
|
Factory::getApplication()->enqueueMessage(Text::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN'), 'error');
|
|
Factory::getApplication()->redirect(Route::_('index.php', false));
|
|
|
|
return;
|
|
}
|
|
|
|
return parent::display($cachable, $urlparams);
|
|
}
|
|
|
|
// ==================================================================
|
|
// Plugin toggle
|
|
// ==================================================================
|
|
|
|
public function togglePlugin()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('mokowaas.plugins.toggle'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$app = Factory::getApplication();
|
|
$model = $this->getModel('Dashboard');
|
|
|
|
$result = $model->togglePlugin(
|
|
$app->getInput()->getInt('extension_id', 0),
|
|
$app->getInput()->getInt('enabled', 0)
|
|
);
|
|
|
|
$this->jsonResponse($result);
|
|
}
|
|
|
|
// ==================================================================
|
|
// Heartbeat
|
|
// ==================================================================
|
|
|
|
public function sendHeartbeat()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
try
|
|
{
|
|
$monitorPlugin = \Joomla\CMS\Plugin\PluginHelper::getPlugin('system', 'mokowaas_monitor');
|
|
|
|
if (!$monitorPlugin)
|
|
{
|
|
$this->jsonResponse(['success' => false, 'message' => 'Monitor plugin not enabled.']);
|
|
|
|
return;
|
|
}
|
|
|
|
$params = new \Joomla\Registry\Registry($monitorPlugin->params);
|
|
$baseUrl = rtrim($params->get('base_url', ''), '/');
|
|
|
|
// Fall back to manifest XML default if not yet saved in params
|
|
if (empty($baseUrl))
|
|
{
|
|
$manifestFile = JPATH_PLUGINS . '/system/mokowaas_monitor/mokowaas_monitor.xml';
|
|
|
|
if (is_file($manifestFile))
|
|
{
|
|
$xml = simplexml_load_file($manifestFile);
|
|
|
|
if ($xml)
|
|
{
|
|
foreach ($xml->xpath('//field[@name="base_url"]') as $field)
|
|
{
|
|
$baseUrl = rtrim((string) $field['default'], '/');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (empty($baseUrl))
|
|
{
|
|
$this->jsonResponse(['success' => false, 'message' => 'MokoWaaSHQ URL not configured in monitor plugin.']);
|
|
|
|
return;
|
|
}
|
|
|
|
$corePlugin = \Joomla\CMS\Plugin\PluginHelper::getPlugin('system', 'mokowaas');
|
|
$coreParams = new \Joomla\Registry\Registry($corePlugin ? $corePlugin->params : '{}');
|
|
$healthToken = $coreParams->get('health_api_token', '');
|
|
|
|
if (empty($healthToken))
|
|
{
|
|
$this->jsonResponse(['success' => false, 'message' => 'Health token not configured.']);
|
|
|
|
return;
|
|
}
|
|
|
|
$siteUrl = rtrim(\Joomla\CMS\Uri\Uri::root(), '/');
|
|
$domain = parse_url($siteUrl, PHP_URL_HOST) ?: '';
|
|
$timestamp = time();
|
|
|
|
$payload = json_encode([
|
|
'token' => $healthToken,
|
|
'domain' => $domain,
|
|
'site_name' => Factory::getConfig()->get('sitename', 'Joomla'),
|
|
'site_url' => $siteUrl,
|
|
'joomla_version' => (new \Joomla\CMS\Version())->getShortVersion(),
|
|
'php_version' => PHP_VERSION,
|
|
'timestamp' => $timestamp,
|
|
], JSON_UNESCAPED_SLASHES);
|
|
|
|
// RSA sign the request
|
|
$headers = ['Content-Type: application/json'];
|
|
$signingKeyB64 = $params->get('signing_key', '');
|
|
|
|
// Fall back to manifest XML default if not yet saved in params
|
|
if (empty($signingKeyB64))
|
|
{
|
|
$manifestFile = JPATH_PLUGINS . '/system/mokowaas_monitor/mokowaas_monitor.xml';
|
|
|
|
if (is_file($manifestFile))
|
|
{
|
|
$xml = simplexml_load_file($manifestFile);
|
|
|
|
if ($xml)
|
|
{
|
|
foreach ($xml->xpath('//field[@name="signing_key"]') as $field)
|
|
{
|
|
$signingKeyB64 = (string) $field['default'];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!empty($signingKeyB64))
|
|
{
|
|
$privateKeyPem = base64_decode($signingKeyB64);
|
|
$privateKey = openssl_pkey_get_private($privateKeyPem);
|
|
|
|
if ($privateKey !== false)
|
|
{
|
|
$message = $domain . '|' . $timestamp . '|' . $healthToken;
|
|
$signature = '';
|
|
|
|
if (openssl_sign($message, $signature, $privateKey, OPENSSL_ALGO_SHA256))
|
|
{
|
|
$headers[] = 'X-MokoWaaS-Signature: ' . base64_encode($signature);
|
|
$headers[] = 'X-MokoWaaS-Timestamp: ' . $timestamp;
|
|
}
|
|
}
|
|
}
|
|
|
|
$endpoint = $baseUrl . '/api/index.php/v1/mokowaashq/heartbeat';
|
|
|
|
$ch = curl_init($endpoint);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_POST => true,
|
|
CURLOPT_HTTPHEADER => $headers,
|
|
CURLOPT_POSTFIELDS => $payload,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => 15,
|
|
CURLOPT_FOLLOWLOCATION => true,
|
|
CURLOPT_SSL_VERIFYPEER => false,
|
|
]);
|
|
|
|
$response = curl_exec($ch);
|
|
$code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$error = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
if ($error)
|
|
{
|
|
$this->jsonResponse(['success' => false, 'message' => 'Connection failed: ' . $error]);
|
|
}
|
|
elseif ($code >= 200 && $code < 300)
|
|
{
|
|
$body = json_decode($response, true);
|
|
$this->jsonResponse(['success' => true, 'message' => 'Heartbeat sent: ' . ($body['status'] ?? 'ok')]);
|
|
}
|
|
else
|
|
{
|
|
$body = json_decode($response, true);
|
|
$this->jsonResponse(['success' => false, 'message' => 'HTTP ' . $code . ': ' . ($body['error'] ?? $body['message'] ?? 'Unknown')]);
|
|
}
|
|
}
|
|
catch (\Throwable $e)
|
|
{
|
|
$this->jsonResponse(['success' => false, 'message' => 'Error: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
// Cache
|
|
// ==================================================================
|
|
|
|
public function clearCache()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('mokowaas.cache'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$this->jsonResponse($this->getModel('Dashboard')->clearCache());
|
|
}
|
|
|
|
public function clearTemp()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('mokowaas.cache'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$this->jsonResponse($this->getModel('Dashboard')->clearTemp());
|
|
}
|
|
|
|
// ==================================================================
|
|
// Extensions
|
|
// ==================================================================
|
|
|
|
public function installExtension()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('mokowaas.extensions'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$downloadUrl = Factory::getApplication()->getInput()->getString('download_url', '');
|
|
|
|
if (empty($downloadUrl))
|
|
{
|
|
$this->jsonResponse(['success' => false, 'message' => 'Missing download URL.']);
|
|
return;
|
|
}
|
|
|
|
$this->jsonResponse($this->getModel('Extensions')->installFromUrl($downloadUrl));
|
|
}
|
|
|
|
// ==================================================================
|
|
// .htaccess
|
|
// ==================================================================
|
|
|
|
public function saveHtaccess()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('mokowaas.htaccess'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$app = Factory::getApplication();
|
|
$input = $app->getInput();
|
|
$model = $this->getModel('Htaccess');
|
|
|
|
$options = [];
|
|
|
|
foreach ($input->getArray() as $key => $value)
|
|
{
|
|
if (str_starts_with($key, 'opt_'))
|
|
{
|
|
$options[substr($key, 4)] = $value;
|
|
}
|
|
}
|
|
|
|
if (!empty($options))
|
|
{
|
|
$model->saveOptions($options);
|
|
}
|
|
|
|
$this->jsonResponse($model->saveHtaccess($input->getRaw('content', '')));
|
|
}
|
|
|
|
public function generateHtaccess()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('mokowaas.htaccess'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$model = $this->getModel('Htaccess');
|
|
$options = Factory::getApplication()->getInput()->getArray();
|
|
|
|
$model->saveOptions($options);
|
|
|
|
$app = Factory::getApplication();
|
|
$app->setHeader('Content-Type', 'application/json');
|
|
echo json_encode([
|
|
'htaccess' => $model->generateHtaccess($options),
|
|
'nginx' => $model->generateNginx($options),
|
|
]);
|
|
$app->close();
|
|
}
|
|
|
|
// ==================================================================
|
|
// Tickets
|
|
// ==================================================================
|
|
|
|
public function createTicket()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('mokowaas.tickets.create'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$input = Factory::getApplication()->getInput();
|
|
|
|
$this->jsonResponse($this->getModel('Tickets')->createTicket([
|
|
'subject' => $input->getString('subject', ''),
|
|
'body' => $input->getRaw('body', ''),
|
|
'priority' => $input->getString('priority', 'normal'),
|
|
'category_id' => $input->getInt('category_id', 0),
|
|
]));
|
|
}
|
|
|
|
public function addTicketReply()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('mokowaas.tickets'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$input = Factory::getApplication()->getInput();
|
|
|
|
$this->jsonResponse($this->getModel('Tickets')->addReply(
|
|
$input->getInt('ticket_id', 0),
|
|
$input->getRaw('body', ''),
|
|
(bool) $input->getInt('is_internal', 0)
|
|
));
|
|
}
|
|
|
|
public function updateTicketStatus()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('mokowaas.tickets'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$input = Factory::getApplication()->getInput();
|
|
|
|
$this->jsonResponse($this->getModel('Tickets')->updateStatus(
|
|
$input->getInt('ticket_id', 0),
|
|
$input->getString('status', '')
|
|
));
|
|
}
|
|
|
|
// ==================================================================
|
|
// KB Search
|
|
// ==================================================================
|
|
|
|
public function searchKb()
|
|
{
|
|
$query = Factory::getApplication()->getInput()->getString('q', '');
|
|
|
|
if (strlen($query) < 3)
|
|
{
|
|
$this->jsonResponse(['results' => []]);
|
|
}
|
|
|
|
try
|
|
{
|
|
$db = Factory::getDbo();
|
|
$escaped = $db->quote('%' . $db->escape($query, true) . '%');
|
|
|
|
$results = $db->setQuery(
|
|
$db->getQuery(true)
|
|
->select([$db->quoteName('l.title'), $db->quoteName('l.url'), $db->quoteName('l.description')])
|
|
->from($db->quoteName('#__finder_links', 'l'))
|
|
->where($db->quoteName('l.published') . ' = 1')
|
|
->where('(' . $db->quoteName('l.title') . ' LIKE ' . $escaped
|
|
. ' OR ' . $db->quoteName('l.description') . ' LIKE ' . $escaped . ')')
|
|
->order($db->quoteName('l.title') . ' ASC')
|
|
->setLimit(8)
|
|
)->loadObjectList() ?: [];
|
|
|
|
foreach ($results as $r)
|
|
{
|
|
$r->description = mb_substr(strip_tags($r->description ?? ''), 0, 150);
|
|
}
|
|
|
|
$this->jsonResponse(['results' => $results]);
|
|
}
|
|
catch (\Throwable $e)
|
|
{
|
|
$this->jsonResponse(['results' => []]);
|
|
}
|
|
}
|
|
|
|
// ==================================================================
|
|
// Maintenance (#127, #128)
|
|
// ==================================================================
|
|
|
|
public function optimizeDb()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); return; }
|
|
$model = new \Moko\Component\MokoWaaS\Administrator\Model\MaintenanceModel();
|
|
$this->jsonResponse($model->optimizeTables());
|
|
}
|
|
|
|
public function repairDb()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); return; }
|
|
$model = new \Moko\Component\MokoWaaS\Administrator\Model\MaintenanceModel();
|
|
$this->jsonResponse($model->repairTables());
|
|
}
|
|
|
|
public function purgeSessions()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); return; }
|
|
$model = new \Moko\Component\MokoWaaS\Administrator\Model\MaintenanceModel();
|
|
$this->jsonResponse($model->purgeSessions());
|
|
}
|
|
|
|
public function cleanDirectory()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
if (!$this->checkAcl('mokowaas.cache')) { $this->jsonForbidden(); return; }
|
|
$dirKey = Factory::getApplication()->getInput()->getString('dir_key', '');
|
|
$model = new \Moko\Component\MokoWaaS\Administrator\Model\MaintenanceModel();
|
|
$this->jsonResponse($model->cleanDirectory($dirKey));
|
|
}
|
|
|
|
// ==================================================================
|
|
// Helpdesk CRUD (#137, #138, #139)
|
|
// ==================================================================
|
|
|
|
public function saveCategory()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
if (!$this->checkAcl('mokowaas.tickets')) { $this->jsonForbidden(); }
|
|
$input = Factory::getApplication()->getInput();
|
|
$db = Factory::getDbo();
|
|
$id = $input->getInt('id', 0);
|
|
$data = (object) [
|
|
'title' => $input->getString('title', ''),
|
|
'alias' => \Joomla\CMS\Filter\OutputFilter::stringURLSafe($input->getString('title', '')),
|
|
'sla_response_minutes' => $input->getInt('sla_response_minutes', 480),
|
|
'sla_resolution_minutes' => $input->getInt('sla_resolution_minutes', 2880),
|
|
'auto_assign_user' => $input->getInt('auto_assign_user', 0) ?: null,
|
|
'published' => $input->getInt('published', 1),
|
|
];
|
|
if ($id) {
|
|
$data->id = $id;
|
|
$db->updateObject('#__mokowaas_ticket_categories', $data, 'id');
|
|
} else {
|
|
$data->ordering = 0;
|
|
$db->insertObject('#__mokowaas_ticket_categories', $data, 'id');
|
|
}
|
|
$this->jsonResponse(['success' => true, 'message' => 'Category saved.', 'id' => (int) $data->id]);
|
|
}
|
|
|
|
public function deleteCategory()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
if (!$this->checkAcl('mokowaas.tickets')) { $this->jsonForbidden(); }
|
|
$db = Factory::getDbo();
|
|
$db->setQuery($db->getQuery(true)->delete('#__mokowaas_ticket_categories')->where('id = ' . Factory::getApplication()->getInput()->getInt('id', 0)))->execute();
|
|
$this->jsonResponse(['success' => true, 'message' => 'Category deleted.']);
|
|
}
|
|
|
|
public function saveCanned()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
if (!$this->checkAcl('mokowaas.tickets')) { $this->jsonForbidden(); }
|
|
$input = Factory::getApplication()->getInput();
|
|
$db = Factory::getDbo();
|
|
$data = (object) [
|
|
'title' => $input->getString('title', ''),
|
|
'body' => $input->getRaw('body', ''),
|
|
'category_id' => $input->getInt('category_id', 0) ?: null,
|
|
'ordering' => 0,
|
|
];
|
|
$id = $input->getInt('id', 0);
|
|
if ($id) { $data->id = $id; $db->updateObject('#__mokowaas_ticket_canned', $data, 'id'); }
|
|
else { $db->insertObject('#__mokowaas_ticket_canned', $data, 'id'); }
|
|
$this->jsonResponse(['success' => true, 'message' => 'Canned response saved.', 'id' => (int) $data->id]);
|
|
}
|
|
|
|
public function deleteCanned()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
if (!$this->checkAcl('mokowaas.tickets')) { $this->jsonForbidden(); }
|
|
$db = Factory::getDbo();
|
|
$db->setQuery($db->getQuery(true)->delete('#__mokowaas_ticket_canned')->where('id = ' . Factory::getApplication()->getInput()->getInt('id', 0)))->execute();
|
|
$this->jsonResponse(['success' => true, 'message' => 'Canned response deleted.']);
|
|
}
|
|
|
|
public function saveAutomation()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); }
|
|
$input = Factory::getApplication()->getInput();
|
|
$db = Factory::getDbo();
|
|
$data = (object) [
|
|
'title' => $input->getString('title', ''),
|
|
'trigger_event' => $input->getString('trigger_event', 'ticket_created'),
|
|
'conditions' => $input->getRaw('conditions', '[]'),
|
|
'actions' => $input->getRaw('actions', '[]'),
|
|
'enabled' => 1,
|
|
'ordering' => 0,
|
|
];
|
|
$id = $input->getInt('id', 0);
|
|
if ($id) { $data->id = $id; $db->updateObject('#__mokowaas_ticket_automation', $data, 'id'); }
|
|
else { $db->insertObject('#__mokowaas_ticket_automation', $data, 'id'); }
|
|
$this->jsonResponse(['success' => true, 'message' => 'Rule saved.', 'id' => (int) $data->id]);
|
|
}
|
|
|
|
public function deleteAutomation()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); }
|
|
$db = Factory::getDbo();
|
|
$db->setQuery($db->getQuery(true)->delete('#__mokowaas_ticket_automation')->where('id = ' . Factory::getApplication()->getInput()->getInt('id', 0)))->execute();
|
|
$this->jsonResponse(['success' => true, 'message' => 'Rule deleted.']);
|
|
}
|
|
|
|
public function toggleAutomation()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
if (!$this->checkAcl('core.admin')) { $this->jsonForbidden(); }
|
|
$input = Factory::getApplication()->getInput();
|
|
$db = Factory::getDbo();
|
|
$db->setQuery($db->getQuery(true)->update('#__mokowaas_ticket_automation')
|
|
->set('enabled = ' . $input->getInt('enabled', 0))
|
|
->where('id = ' . $input->getInt('id', 0)))->execute();
|
|
$this->jsonResponse(['success' => true, 'message' => 'Rule updated.']);
|
|
}
|
|
|
|
// ==================================================================
|
|
// Settings Import/Export (#132)
|
|
// ==================================================================
|
|
|
|
public function exportSettings()
|
|
{
|
|
Session::checkToken('get') or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('core.admin'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$db = Factory::getDbo();
|
|
$settings = [];
|
|
|
|
// Export all MokoWaaS plugin params
|
|
$plugins = ['mokowaas', 'mokowaas_firewall', 'mokowaas_tenant', 'mokowaas_devtools', 'mokowaas_offline'];
|
|
|
|
foreach ($plugins as $element)
|
|
{
|
|
$db->setQuery(
|
|
$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('system'))
|
|
);
|
|
$settings['plugins'][$element] = json_decode($db->loadResult() ?? '{}', true);
|
|
}
|
|
|
|
// Export component params
|
|
$db->setQuery(
|
|
$db->getQuery(true)
|
|
->select($db->quoteName('params'))
|
|
->from($db->quoteName('#__extensions'))
|
|
->where($db->quoteName('element') . ' = ' . $db->quote('com_mokowaas'))
|
|
->where($db->quoteName('type') . ' = ' . $db->quote('component'))
|
|
);
|
|
$settings['component'] = json_decode($db->loadResult() ?? '{}', true);
|
|
$settings['exported'] = gmdate('Y-m-d\TH:i:s\Z');
|
|
$settings['site'] = Factory::getConfig()->get('sitename', '');
|
|
|
|
$this->jsonResponse(['success' => true, 'settings' => $settings]);
|
|
}
|
|
|
|
public function importSettings()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('core.admin'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$json = Factory::getApplication()->getInput()->getRaw('settings_json', '');
|
|
$data = json_decode($json, true);
|
|
|
|
if (empty($data) || empty($data['plugins']))
|
|
{
|
|
$this->jsonResponse(['success' => false, 'message' => 'Invalid settings JSON.']);
|
|
return;
|
|
}
|
|
|
|
$db = Factory::getDbo();
|
|
$count = 0;
|
|
|
|
foreach ($data['plugins'] ?? [] as $element => $params)
|
|
{
|
|
if (!is_array($params))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
$db->setQuery(
|
|
$db->getQuery(true)
|
|
->update($db->quoteName('#__extensions'))
|
|
->set($db->quoteName('params') . ' = ' . $db->quote(json_encode($params)))
|
|
->where($db->quoteName('element') . ' = ' . $db->quote($element))
|
|
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
|
|
->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
|
|
)->execute();
|
|
$count++;
|
|
}
|
|
|
|
if (!empty($data['component']) && is_array($data['component']))
|
|
{
|
|
$db->setQuery(
|
|
$db->getQuery(true)
|
|
->update($db->quoteName('#__extensions'))
|
|
->set($db->quoteName('params') . ' = ' . $db->quote(json_encode($data['component'])))
|
|
->where($db->quoteName('element') . ' = ' . $db->quote('com_mokowaas'))
|
|
->where($db->quoteName('type') . ' = ' . $db->quote('component'))
|
|
)->execute();
|
|
$count++;
|
|
}
|
|
|
|
$this->jsonResponse(['success' => true, 'message' => "Imported settings for {$count} extensions."]);
|
|
}
|
|
|
|
// ==================================================================
|
|
// WAF Log
|
|
// ==================================================================
|
|
|
|
public function purgeWafLog()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('core.admin'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$days = Factory::getApplication()->getInput()->getInt('days', 30);
|
|
$model = new \Moko\Component\MokoWaaS\Administrator\Model\WaflogModel();
|
|
|
|
$this->jsonResponse($model->purgeLogs($days));
|
|
}
|
|
|
|
public function banIpFromLog()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('core.admin'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$ip = Factory::getApplication()->getInput()->getString('ip', '');
|
|
$model = new \Moko\Component\MokoWaaS\Administrator\Model\WaflogModel();
|
|
|
|
$this->jsonResponse($model->banIp($ip));
|
|
}
|
|
|
|
// ==================================================================
|
|
// Privacy Guard
|
|
// ==================================================================
|
|
|
|
public function processDataRequest()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('core.admin'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$input = Factory::getApplication()->getInput();
|
|
$model = new \Moko\Component\MokoWaaS\Administrator\Model\PrivacyModel();
|
|
$action = $input->getString('action', 'deny');
|
|
|
|
if ($action === 'create')
|
|
{
|
|
$result = $model->createRequest(
|
|
$input->getInt('user_id', 0),
|
|
$input->getString('type', 'export')
|
|
);
|
|
$this->jsonResponse($result);
|
|
return;
|
|
}
|
|
|
|
if ($action === 'approve' && !$input->getInt('request_id', 0) && $input->getInt('user_id', 0))
|
|
{
|
|
// Auto-process: create then immediately approve
|
|
$result = $model->createRequest(
|
|
$input->getInt('user_id', 0),
|
|
$input->getString('type', 'export')
|
|
);
|
|
|
|
if ($result['success'] && !empty($result['id']))
|
|
{
|
|
$result = $model->processRequest((int) $result['id'], 'approve');
|
|
}
|
|
|
|
$this->jsonResponse($result);
|
|
return;
|
|
}
|
|
|
|
$this->jsonResponse($model->processRequest(
|
|
$input->getInt('request_id', 0),
|
|
$action
|
|
));
|
|
}
|
|
|
|
public function exportUserData()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('core.admin'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$model = new \Moko\Component\MokoWaaS\Administrator\Model\PrivacyModel();
|
|
|
|
$this->jsonResponse($model->exportUserData(
|
|
Factory::getApplication()->getInput()->getInt('user_id', 0)
|
|
));
|
|
}
|
|
|
|
// ==================================================================
|
|
// Importers
|
|
// ==================================================================
|
|
|
|
public function importAts()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('mokowaas.tickets'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$this->jsonResponse($this->getModel('Import')->importAts());
|
|
}
|
|
|
|
public function importAdminTools()
|
|
{
|
|
Session::checkToken() or die(Text::_('JINVALID_TOKEN'));
|
|
|
|
if (!$this->checkAcl('core.admin'))
|
|
{
|
|
$this->jsonForbidden();
|
|
return;
|
|
}
|
|
|
|
$this->jsonResponse($this->getModel('Import')->importAdminTools());
|
|
}
|
|
|
|
// ==================================================================
|
|
// Helpers
|
|
// ==================================================================
|
|
|
|
/**
|
|
* Check a MokoWaaS ACL permission for the current user.
|
|
*/
|
|
private function checkAcl(string $action): bool
|
|
{
|
|
$user = Factory::getApplication()->getIdentity();
|
|
|
|
// Super admins always pass
|
|
if ($user->authorise('core.admin', 'com_mokowaas'))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return $user->authorise($action, 'com_mokowaas');
|
|
}
|
|
|
|
/**
|
|
* Send a JSON response and close.
|
|
*/
|
|
private function jsonResponse(array $data): void
|
|
{
|
|
$app = Factory::getApplication();
|
|
$app->setHeader('Content-Type', 'application/json');
|
|
echo json_encode($data);
|
|
$app->close();
|
|
}
|
|
|
|
/**
|
|
* Send a 403 JSON response and close.
|
|
*/
|
|
private function jsonForbidden(): void
|
|
{
|
|
$this->jsonResponse(['success' => false, 'message' => Text::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN')]);
|
|
return;
|
|
}
|
|
|
|
}
|