00d44256b4
Rebrand all 17 sub-extensions from mokowaas to mokosuite naming, including component, plugins, modules, task plugins, and webservices. Updates package manifest, workflows, docs, wiki, and issue templates. Adds new plg_system_mokosuite_license extension.
174 lines
4.2 KiB
PHP
174 lines
4.2 KiB
PHP
<?php
|
|
/**
|
|
* @package MokoSuite
|
|
* @subpackage com_mokosuite
|
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
|
* @license GNU General Public License version 3 or later; see LICENSE
|
|
*/
|
|
|
|
namespace Moko\Component\MokoSuite\Api\Controller;
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
use Joomla\CMS\Factory;
|
|
use Joomla\CMS\MVC\Controller\BaseController;
|
|
use Joomla\CMS\Plugin\PluginHelper;
|
|
use Joomla\CMS\Uri\Uri;
|
|
use Joomla\Registry\Registry;
|
|
|
|
/**
|
|
* Remote login API controller.
|
|
*
|
|
* POST /api/index.php/v1/mokosuite/remote-login
|
|
* Body: {"token": "health_api_token", "user": "requesting_username", "origin": "MokoSuiteHQ"}
|
|
*
|
|
* Validates the health API token, generates a one-time login token
|
|
* for the master user, and returns a URL that auto-authenticates.
|
|
*
|
|
* @since 02.35.00
|
|
*/
|
|
class RemoteLoginController extends BaseController
|
|
{
|
|
/**
|
|
* One-time token validity in seconds.
|
|
*/
|
|
private const OTL_TTL = 60;
|
|
|
|
/**
|
|
* Generate a one-time login URL for the master user.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function execute($task = 'remoteLogin'): void
|
|
{
|
|
$app = Factory::getApplication();
|
|
$input = $app->getInput()->json;
|
|
|
|
$token = $input->get('token', '', 'RAW');
|
|
$origin = $input->get('origin', '', 'STRING');
|
|
|
|
if (empty($token))
|
|
{
|
|
$this->sendJson(401, ['error' => 'Missing token']);
|
|
|
|
return;
|
|
}
|
|
|
|
// Validate against the core plugin's health_api_token
|
|
$plugin = PluginHelper::getPlugin('system', 'mokosuite');
|
|
|
|
if (!$plugin)
|
|
{
|
|
$this->sendJson(503, ['error' => 'MokoSuite core plugin not found']);
|
|
|
|
return;
|
|
}
|
|
|
|
$params = new Registry($plugin->params);
|
|
$healthToken = $params->get('health_api_token', '');
|
|
|
|
if (empty($healthToken) || !hash_equals($healthToken, $token))
|
|
{
|
|
$this->sendJson(401, ['error' => 'Invalid token']);
|
|
|
|
return;
|
|
}
|
|
|
|
// Find the master user
|
|
$masterUsernames = $this->getMasterUsernames($params);
|
|
|
|
if (empty($masterUsernames))
|
|
{
|
|
$this->sendJson(403, ['error' => 'No master user configured']);
|
|
|
|
return;
|
|
}
|
|
|
|
// Use the first master username
|
|
$masterUsername = $masterUsernames[0];
|
|
|
|
// Look up the user
|
|
$db = Factory::getDbo();
|
|
$db->setQuery(
|
|
$db->getQuery(true)
|
|
->select([$db->quoteName('id'), $db->quoteName('username')])
|
|
->from($db->quoteName('#__users'))
|
|
->where($db->quoteName('username') . ' = ' . $db->quote($masterUsername))
|
|
->where($db->quoteName('block') . ' = 0')
|
|
);
|
|
$user = $db->loadObject();
|
|
|
|
if (!$user)
|
|
{
|
|
$this->sendJson(403, ['error' => 'Master user not found or blocked']);
|
|
|
|
return;
|
|
}
|
|
|
|
// Generate one-time login token
|
|
$otlToken = bin2hex(random_bytes(32));
|
|
$expires = time() + self::OTL_TTL;
|
|
|
|
// Store in a temp file (avoids DB schema changes)
|
|
$otlFile = JPATH_ADMINISTRATOR . '/cache/mokosuite_otl_' . md5($otlToken) . '.json';
|
|
file_put_contents($otlFile, json_encode([
|
|
'token' => $otlToken,
|
|
'user_id' => (int) $user->id,
|
|
'username' => $user->username,
|
|
'expires' => $expires,
|
|
'origin' => substr($origin, 0, 100),
|
|
]));
|
|
|
|
// Build login URL
|
|
$loginUrl = rtrim(Uri::root(), '/') . '/administrator/index.php?mokosuite_otl=' . $otlToken;
|
|
|
|
$this->sendJson(200, [
|
|
'status' => 'ok',
|
|
'login_url' => $loginUrl,
|
|
'expires' => $expires,
|
|
'user' => $user->username,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Decode master usernames from plugin params.
|
|
*
|
|
* @param Registry $params Plugin params.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function getMasterUsernames(Registry $params): array
|
|
{
|
|
// Use MokoSuiteHelper if available
|
|
$helperFile = JPATH_PLUGINS . '/system/mokosuite/Helper/MokoSuiteHelper.php';
|
|
|
|
if (file_exists($helperFile))
|
|
{
|
|
require_once $helperFile;
|
|
|
|
if (method_exists(\Moko\Plugin\System\MokoSuite\Helper\MokoSuiteHelper::class, 'getMasterUsernames'))
|
|
{
|
|
return \Moko\Plugin\System\MokoSuite\Helper\MokoSuiteHelper::getMasterUsernames();
|
|
}
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* Send JSON response and terminate.
|
|
*
|
|
* @param int $code HTTP status code.
|
|
* @param array $data Response data.
|
|
*
|
|
* @return void
|
|
*/
|
|
private function sendJson(int $code, array $data): void
|
|
{
|
|
http_response_code($code);
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
echo json_encode($data, JSON_UNESCAPED_SLASHES);
|
|
Factory::getApplication()->close();
|
|
}
|
|
}
|