This commit is contained in:
2026-03-07 00:33:27 +01:00
parent 2f673e8710
commit 497ad6c017
2 changed files with 141 additions and 5 deletions

View File

@@ -353,12 +353,35 @@
}
return;
}
const formData = new FormData(consoleForm);
if (presetSelect) formData.set('terminal_preset_id', '');
const url = new URL(window.location.href);
url.searchParams.set('send_active_json', '1');
fetch(url.toString(), { method: 'POST', body: formData, cache: 'no-store' })
.then((res) => res.json())
.then((data) => {
if (data.ok) {
if (consoleNotice) {
consoleNotice.textContent = 'Bestehende Konsole kann nicht direkt gesteuert werden Befehl wird in neuer Konsole ausgeführt.';
consoleNotice.textContent = data.notice || 'Befehl wurde in der bestehenden Konsole ausgeführt.';
consoleNotice.style.display = 'block';
}
if (consoleError) consoleError.style.display = 'none';
return;
}
if (consoleNotice) {
consoleNotice.textContent = data.error || 'Bestehende Konsole nicht verfügbar Befehl wird in neuer Konsole ausgeführt.';
consoleNotice.style.display = 'block';
}
submitOpen();
})
.catch(() => {
if (consoleNotice) {
consoleNotice.textContent = 'Bestehende Konsole nicht verfügbar Befehl wird in neuer Konsole ausgeführt.';
consoleNotice.style.display = 'block';
}
submitOpen();
});
});
}
}
})();

View File

@@ -295,6 +295,59 @@ if (isset($_GET['run_command_json'])) {
exit;
}
if (isset($_GET['send_active_json'])) {
$hostId = (int)($_POST['terminal_host_id'] ?? 0);
$commandId = (int)($_POST['terminal_preset_id'] ?? 0);
$rawCommand = trim((string)($_POST['terminal_command_text'] ?? ''));
$error = null;
$notice = null;
if ($hostId <= 0) {
$error = 'Bitte einen Host wählen.';
} elseif ($commandId <= 0 && $rawCommand === '') {
$error = 'Bitte einen Befehl wählen oder einen Befehl eingeben.';
} else {
$selectedCommand = '';
if ($commandId > 0) {
foreach ($commands as $c) {
if ((int)$c['id'] === $commandId) {
if (!auth_is_admin() && !empty($c['admin_only'])) {
$error = 'Dieser Befehl ist nur für Admins.';
} else {
$selectedCommand = (string)$c['command'];
}
break;
}
}
}
if (!$error) {
$commandText = $selectedCommand !== '' ? $selectedCommand : $rawCommand;
$stmt = $pdo->prepare('SELECT * FROM ' . $table('hosts') . ' WHERE id = :id LIMIT 1');
$stmt->execute(['id' => $hostId]);
$host = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$host) {
$error = 'Host nicht gefunden.';
} else {
$strictHostKey = getenv('PI_CONTROL_STRICT_HOSTKEY') === '1';
[$ok, $sendError] = sendToActiveConsole($host, $commandText, $strictHostKey);
if ($ok) {
$notice = 'Befehl wurde in der bestehenden Konsole ausgeführt.';
} else {
$error = $sendError ?: 'Bestehende Konsole nicht verfügbar.';
}
}
}
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode([
'ok' => $error === null,
'error' => $error,
'notice' => $notice,
]);
exit;
}
// Form submits are handled via AJAX to avoid reloads.
$runs = $pdo->query(
@@ -303,6 +356,66 @@ $runs = $pdo->query(
LEFT JOIN ' . $table('hosts') . ' h ON h.id = r.host_id
ORDER BY r.id DESC LIMIT 20'
)->fetchAll(PDO::FETCH_ASSOC);
function sendToActiveConsole(array $host, string $command, bool $strictHostKey): array
{
$hostAddr = (string)($host['host'] ?? '');
$user = (string)($host['username'] ?? '');
$port = (int)($host['port'] ?? 22);
$authType = (string)($host['auth_type'] ?? 'key');
$keyPath = (string)($host['key_path'] ?? '');
$password = (string)($host['password'] ?? '');
if ($hostAddr === '' || $user === '') {
return [false, 'Hostdaten unvollständig.'];
}
$opts = $strictHostKey
? '-o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/root/.ssh/known_hosts'
: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null';
$target = escapeshellarg($user . '@' . $hostAddr);
$cmdB64 = base64_encode($command);
$remote = 'CMD_B64="$0"; CMD="$(printf "%s" "$CMD_B64" | base64 -d)"; ' .
'command -v tmux >/dev/null 2>&1 || exit 2; ' .
'tmux has-session -t nexus 2>/dev/null || exit 3; ' .
'tmux send-keys -t nexus "$CMD" C-m';
$cmd = 'ssh ' . $opts . ' -p ' . (int)$port . ' ';
if ($authType === 'key' && $keyPath !== '') {
$cmd .= '-i ' . escapeshellarg($keyPath) . ' ';
}
$cmd .= $target . ' -- /bin/bash -lc ' . escapeshellarg($remote) . ' ' . escapeshellarg($cmdB64);
if ($authType === 'pass' && $password !== '') {
$cmd = 'sshpass -p ' . escapeshellarg($password) . ' ' . $cmd;
}
$descriptors = [
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
$process = proc_open($cmd, $descriptors, $pipes);
if (!is_resource($process)) {
return [false, 'proc_open failed'];
}
$out = stream_get_contents($pipes[1]);
$err = stream_get_contents($pipes[2]);
$status = proc_get_status($process);
$exitCode = (int)($status['exitcode'] ?? 1);
proc_close($process);
if ($exitCode === 0) {
return [true, null];
}
if ($exitCode === 2) {
return [false, 'tmux ist auf dem Host nicht installiert.'];
}
if ($exitCode === 3) {
return [false, 'Keine aktive Konsole gefunden.'];
}
$msg = trim($err !== '' ? $err : $out);
return [false, $msg !== '' ? $msg : 'Befehl konnte nicht gesendet werden.'];
}
?>
<div class="card">
<div class="pill">Pi Control</div>