$definition) {
$formValues[$field] = field_value_from_request($field, $_POST + $_GET, $fieldDefs);
}
if ($formValues['target'] === '') {
$formValues['target'] = default_target_for_profile($selectedProfile);
}
$message = '';
$messageType = 'ok';
$resultOutput = '';
$resultCode = null;
$commandPreview = '';
if (isset($_GET['logout'])) {
$_SESSION = [];
session_destroy();
header('Location: index.php?lang=' . urlencode($lang));
exit;
}
if (($_POST['form'] ?? '') === 'login') {
$postedLang = detect_lang(supported_languages());
$_SESSION['lang'] = $postedLang;
$lang = $postedLang;
$loginIp = client_ip_address();
$remainingLock = remaining_lock_seconds($config, $loginIp);
if ($remainingLock > 0) {
$minutes = (int)max(1, ceil($remainingLock / 60));
$message = str_replace('{minutes}', (string)$minutes, t($lang, 'login_locked'));
$messageType = 'error';
append_auth_audit_log($config, $loginIp, 'login_blocked', 'remaining_seconds=' . $remainingLock);
} elseif (!verify_csrf($_POST['csrf'] ?? null)) {
$message = t($lang, 'csrf_error');
$messageType = 'error';
append_auth_audit_log($config, $loginIp, 'csrf_invalid', 'login-form');
} else {
$password = (string)($_POST['password'] ?? '');
$expected = (string)($config['web_password'] ?? '');
if ($expected !== '' && hash_equals($expected, $password)) {
register_login_attempt($config, $loginIp, true);
append_auth_audit_log($config, $loginIp, 'login_success');
session_regenerate_id(true);
$_SESSION['auth'] = true;
header('Location: index.php?lang=' . urlencode($lang));
exit;
}
register_login_attempt($config, $loginIp, false);
$remainingAfterFail = remaining_lock_seconds($config, $loginIp);
if ($remainingAfterFail > 0) {
$minutes = (int)max(1, ceil($remainingAfterFail / 60));
$message = str_replace('{minutes}', (string)$minutes, t($lang, 'login_locked'));
append_auth_audit_log($config, $loginIp, 'login_failed_locked', 'remaining_seconds=' . $remainingAfterFail);
} else {
$message = t($lang, 'invalid_login');
append_auth_audit_log($config, $loginIp, 'login_failed_password');
}
$messageType = 'error';
}
}
if (is_logged_in() && (($_POST['form'] ?? '') === 'run')) {
$postedLang = detect_lang(supported_languages());
$_SESSION['lang'] = $postedLang;
$lang = $postedLang;
try {
if (!verify_csrf($_POST['csrf'] ?? null)) {
throw new RuntimeException(t($lang, 'csrf_error'));
}
$request = normalize_run_request($config, $_POST, $lang);
$selectedModule = $request['module'];
$selectedAction = $request['action'];
$selectedProfile = $request['profile'];
$workdir = $request['workdir'];
foreach ($request['fields'] as $field => $value) {
$formValues[$field] = $value;
}
$result = run_whitelisted_action($config, $request);
$resultOutput = (string)($result['output'] ?? '');
$resultCode = (int)($result['exitCode'] ?? 1);
$commandPreview = (string)($result['commandPreview'] ?? '');
if (($result['ok'] ?? false) === true) {
$message = t($lang, 'status_ok') . ' (exit=' . $resultCode . ')';
$messageType = 'ok';
} else {
$message = t($lang, 'status_error') . ' (exit=' . $resultCode . ')';
$messageType = 'error';
}
push_execution_history([
'time' => date('Y-m-d H:i:s'),
'module' => $selectedModule,
'action' => $selectedAction,
'profile' => $selectedProfile,
'exitCode' => $resultCode,
'ok' => $messageType === 'ok',
]);
} catch (Throwable $exception) {
$message = $exception->getMessage();
$messageType = 'error';
$resultCode = 1;
}
}
$moduleCount = count($catalog);
$actionCount = 0;
foreach ($catalog as $moduleData) {
$actionCount += count($moduleData['actions']);
}
$history = execution_history();
$activeAction = $catalog[$selectedModule]['actions'][$selectedAction];
$liveStatus = is_logged_in() ? collect_live_status($config, $selectedProfile, $workdir) : null;
$clientCatalog = [];
foreach ($catalog as $moduleKey => $moduleData) {
$clientCatalog[$moduleKey] = [
'label' => $moduleData['label'],
'description' => $moduleData['description'],
'actions' => [],
];
foreach ($moduleData['actions'] as $actionKey => $actionData) {
$clientCatalog[$moduleKey]['actions'][$actionKey] = [
'label' => $actionData['label'],
'description' => $actionData['description'],
'fields' => $actionData['fields'],
'profiles' => $actionData['profiles'],
];
}
}
$clientFields = [];
foreach ($fieldDefs as $field => $definition) {
$clientFields[$field] = [
'type' => $definition['type'],
'options' => $definition['options'] ?? [],
'target_by_profile' => $definition['target_by_profile'] ?? [],
];
}
function render_input(string $field, array $definition, string $value, string $lang, string $profile): string
{
$label = h(t($lang, $definition['label_key']));
$placeholder = h((string)($definition['placeholder'] ?? ''));
$fieldEscaped = h($field);
$valueEscaped = h($value);
if (($definition['type'] ?? '') === 'select') {
$options = $definition['options'] ?? [];
if ($field === 'target') {
$options = $definition['target_by_profile'][$profile] ?? [];
}
$html = '';
$html .= '';
return $html;
}
$type = ($definition['type'] ?? 'text') === 'password' ? 'password' : 'text';
return ''
. '';
}
?>
= h(t($lang, 'title')) ?>
= h(t($lang, 'hero_badge')) ?>
= h(t($lang, 'title')) ?>
= h(t($lang, 'subtitle_full')) ?>
= h(t($lang, 'login_title')) ?>
= h(t($lang, 'login_intro')) ?>
= h(t($lang, 'feature_title')) ?>
- = h(t($lang, 'feature_modules')) ?>
- = h(t($lang, 'feature_history')) ?>
- = h(t($lang, 'feature_reports')) ?>
- = h(t($lang, 'feature_security')) ?>
= h(t($lang, 'quick_actions')) ?>
= h(t($lang, 'quick_actions_hint')) ?>
'startstop', 'action' => 'start', 'label' => t($lang, 'action_start')],
['module' => 'startstop', 'action' => 'restart', 'label' => t($lang, 'action_restart')],
['module' => 'health', 'action' => 'run', 'label' => t($lang, 'health_run')],
['module' => 'report', 'action' => 'generate', 'label' => t($lang, 'report_generate')],
] as $quick): ?>
= h(t($lang, 'selected_action')) ?>
= h($activeAction['description']) ?>
= h($catalog[$selectedModule]['label']) ?>
= h($activeAction['label']) ?>
= h($selectedProfile) ?>
= h(t($lang, 'live_status_title')) ?>
= h(t($lang, 'live_status_hint')) ?> = h((string)($liveStatus['generatedAt'] ?? '')) ?>
= h(t($lang, 'live_screens')) ?>
= h((string)($liveStatus['screensSummary']['ok'] ?? 0)) ?>/= h((string)($liveStatus['screensSummary']['total'] ?? 0)) ?>
= h(t($lang, 'live_ports')) ?>
= h((string)($liveStatus['portsSummary']['ok'] ?? 0)) ?>/= h((string)($liveStatus['portsSummary']['total'] ?? 0)) ?>
= h(t($lang, 'live_screens')) ?>
= h(t($lang, 'live_unavailable')) ?>
-
= h((string)$item['name']) ?>
= h(!empty($item['ok']) ? t($lang, 'live_up') : t($lang, 'live_down')) ?>
= h(t($lang, 'live_ports')) ?>
= h(t($lang, 'live_unavailable')) ?>
-
= h((string)$item['name']) ?>
= h(!empty($item['ok']) ? t($lang, 'live_listen') : t($lang, 'live_closed')) ?>
= h(t($lang, 'artifact_title')) ?>
= h(t($lang, 'artifact_hint')) ?>
-
= h((string)$artifact['label']) ?>
= h($artifact['path'] !== null ? basename((string)$artifact['path']) : t($lang, 'artifact_missing')) ?>
= h((string)$artifact['age']) ?>
= h(t($lang, 'form_title')) ?>
= h(t($lang, 'hint_full')) ?>
= h(t($lang, 'catalog_title')) ?>
= h(t($lang, 'catalog_hint')) ?>
= h($moduleData['label']) ?>
= h($moduleData['description']) ?>
-
= h($actionData['label']) ?>
= h($actionData['description']) ?>
= h(t($lang, 'execution_result')) ?>
= h(t($lang, 'execution_result_hint')) ?>
= h(t($lang, 'command_preview')) ?>
= h($commandPreview) ?>
= h(t($lang, 'output')) ?>
= h($resultOutput) ?>
= h(t($lang, 'no_result_yet')) ?>
= h(t($lang, 'history_title')) ?>
= h(t($lang, 'history_hint')) ?>
= h(t($lang, 'history_empty')) ?>
-
= h((string)$entry['time']) ?>
= h((string)$entry['module']) ?> / = h((string)$entry['action']) ?> / = h((string)$entry['profile']) ?>
exit== h((string)$entry['exitCode']) ?>