portkey/
ssh.rs

1use anyhow::Result;
2use std::process::Command;
3
4use crate::models::Server;
5
6pub fn connect(server: &Server) -> Result<()> {
7    println!("Connecting to {}@{}:{}...", server.username, server.host, server.port);
8
9    // Check if sshpass is available
10    let sshpass_check = Command::new("which").arg("sshpass").output();
11    let sshpass_available = sshpass_check.is_ok() && sshpass_check.unwrap().status.success();
12
13    if !sshpass_available {
14        eprintln!("❌ sshpass is not installed or not in PATH.");
15        eprintln!("");
16        eprintln!("Install sshpass to use password authentication:");
17        eprintln!("  macOS: brew install hudochenkov/sshpass/sshpass");
18        eprintln!("  Ubuntu/Debian: sudo apt-get install sshpass");
19        eprintln!("  CentOS/RHEL: sudo yum install sshpass");
20        eprintln!("  Arch: sudo pacman -S sshpass");
21        eprintln!("");
22        eprintln!("Alternatively, connect manually:");
23        eprintln!("  {}", server.ssh_command());
24        eprintln!("  Password: {}", server.password);
25        return Ok(());
26    }
27
28    // Use sshpass with env var to avoid password in process args
29    let status = Command::new("sshpass")
30        .env("SSHPASS", &server.password)
31        .arg("-e")
32        .arg("ssh")
33        .arg(format!("{}@{}", server.username, server.host))
34        .arg("-p")
35        .arg(server.port.to_string())
36        .arg("-o")
37        .arg("StrictHostKeyChecking=no")
38        .status()?;
39
40    if !status.success() {
41        eprintln!("❌ SSH connection failed.");
42        eprintln!("Possible causes:\n  - Server unreachable\n  - Invalid credentials\n  - SSH service not running\n  - Port blocked by firewall");
43    }
44
45    Ok(())
46}
47