asda
This commit is contained in:
@@ -353,12 +353,35 @@
|
|||||||
}
|
}
|
||||||
return;
|
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) {
|
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';
|
consoleNotice.style.display = 'block';
|
||||||
}
|
}
|
||||||
submitOpen();
|
submitOpen();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -295,6 +295,59 @@ if (isset($_GET['run_command_json'])) {
|
|||||||
exit;
|
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.
|
// Form submits are handled via AJAX to avoid reloads.
|
||||||
|
|
||||||
$runs = $pdo->query(
|
$runs = $pdo->query(
|
||||||
@@ -303,6 +356,66 @@ $runs = $pdo->query(
|
|||||||
LEFT JOIN ' . $table('hosts') . ' h ON h.id = r.host_id
|
LEFT JOIN ' . $table('hosts') . ' h ON h.id = r.host_id
|
||||||
ORDER BY r.id DESC LIMIT 20'
|
ORDER BY r.id DESC LIMIT 20'
|
||||||
)->fetchAll(PDO::FETCH_ASSOC);
|
)->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="card">
|
||||||
<div class="pill">Pi Control</div>
|
<div class="pill">Pi Control</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user