asda
This commit is contained in:
@@ -353,11 +353,34 @@
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (consoleNotice) {
|
||||
consoleNotice.textContent = 'Bestehende Konsole kann nicht direkt gesteuert werden – Befehl wird in neuer Konsole ausgeführt.';
|
||||
consoleNotice.style.display = 'block';
|
||||
}
|
||||
submitOpen();
|
||||
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 = 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();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user