import sys import os from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QPushButton, QTextEdit, QFileDialog, QLabel) from PyQt6.QtCore import QThread, pyqtSignal import paramiko class SSHThread(QThread): output_received = pyqtSignal(str) def __init__(self, client, command): super().__init__() self.client = client self.command = command def run(self): stdin, stdout, stderr = self.client.exec_command(self.command) for line in stdout: self.output_received.emit(line.strip()) for line in stderr: self.output_received.emit(line.strip()) class SSHWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Enhanced SSH Frontend") self.setGeometry(100, 100, 800, 600) self.client = None central_widget = QWidget() layout = QVBoxLayout() connection_layout = QHBoxLayout() self.host_input = QLineEdit() self.host_input.setPlaceholderText("Host") connection_layout.addWidget(self.host_input) self.user_input = QLineEdit() self.user_input.setPlaceholderText("Username") connection_layout.addWidget(self.user_input) self.password_input = QLineEdit() self.password_input.setPlaceholderText("Password") self.password_input.setEchoMode(QLineEdit.EchoMode.Password) connection_layout.addWidget(self.password_input) self.connect_button = QPushButton("Connect") self.connect_button.clicked.connect(self.connect_ssh) connection_layout.addWidget(self.connect_button) self.disconnect_button = QPushButton("Disconnect") self.disconnect_button.clicked.connect(self.disconnect_ssh) self.disconnect_button.setEnabled(False) connection_layout.addWidget(self.disconnect_button) layout.addLayout(connection_layout) self.output_area = QTextEdit() self.output_area.setReadOnly(True) layout.addWidget(self.output_area) command_layout = QHBoxLayout() self.command_input = QLineEdit() self.command_input.setPlaceholderText("Enter command") command_layout.addWidget(self.command_input) self.execute_button = QPushButton("Execute") self.execute_button.clicked.connect(self.execute_command) command_layout.addWidget(self.execute_button) layout.addLayout(command_layout) file_transfer_layout = QHBoxLayout() self.upload_button = QPushButton("Upload File") self.upload_button.clicked.connect(self.upload_file) file_transfer_layout.addWidget(self.upload_button) self.download_button = QPushButton("Download File") self.download_button.clicked.connect(self.download_file) file_transfer_layout.addWidget(self.download_button) layout.addLayout(file_transfer_layout) self.status_label = QLabel("Not connected") layout.addWidget(self.status_label) central_widget.setLayout(layout) self.setCentralWidget(central_widget) def connect_ssh(self): host = self.host_input.text() username = self.user_input.text() password = self.password_input.text() try: self.client = paramiko.SSHClient() self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.client.connect(hostname=host, username=username, password=password) self.status_label.setText(f"Connected to {host}") self.connect_button.setEnabled(False) self.disconnect_button.setEnabled(True) self.output_area.append(f"Connected to {host}\n") except paramiko.AuthenticationException: self.output_area.append("Authentication failed.\n") except Exception as e: self.output_area.append(f"Error: {str(e)}\n") def disconnect_ssh(self): if self.client: self.client.close() self.client = None self.status_label.setText("Not connected") self.connect_button.setEnabled(True) self.disconnect_button.setEnabled(False) self.output_area.append("Disconnected\n") def execute_command(self): if not self.client: self.output_area.append("Not connected. Please connect first.\n") return command = self.command_input.text() self.output_area.append(f"$ {command}\n") self.command_input.clear() self.ssh_thread = SSHThread(self.client, command) self.ssh_thread.output_received.connect(self.update_output) self.ssh_thread.start() def update_output(self, output): self.output_area.append(output + "\n") def upload_file(self): if not self.client: self.output_area.append("Not connected. Please connect first.\n") return file_path, _ = QFileDialog.getOpenFileName(self, "Select File to Upload") if file_path: try: sftp = self.client.open_sftp() remote_path = f"/home/{self.user_input.text()}/{os.path.basename(file_path)}" sftp.put(file_path, remote_path) sftp.close() self.output_area.append(f"Uploaded {file_path} to {remote_path}\n") except Exception as e: self.output_area.append(f"Upload failed: {str(e)}\n") def download_file(self): if not self.client: self.output_area.append("Not connected. Please connect first.\n") return remote_path, ok = QFileDialog.getText(self, "Download File", "Enter remote file path:") if ok and remote_path: try: sftp = self.client.open_sftp() local_path, _ = QFileDialog.getSaveFileName(self, "Save File As") if local_path: sftp.get(remote_path, local_path) sftp.close() self.output_area.append(f"Downloaded {remote_path} to {local_path}\n") except Exception as e: self.output_area.append(f"Download failed: {str(e)}\n") if __name__ == "__main__": app = QApplication(sys.argv) window = SSHWindow() window.show() sys.exit(app.exec())