Initial commit: sshell project
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
use crate::config::{ConnectionType, CredentialEntry, SshellConfig};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use std::io::Write;
|
||||
use std::process::Command;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
pub fn connect(name: &str, cfg: &SshellConfig) -> Result<()> {
|
||||
let profile = cfg
|
||||
.connections
|
||||
.get(name)
|
||||
.with_context(|| format!("connection {name} not found"))?;
|
||||
crate::ui::restore_terminal()?;
|
||||
match &profile.kind {
|
||||
ConnectionType::Ssh {
|
||||
host,
|
||||
port,
|
||||
user,
|
||||
auth_ref,
|
||||
..
|
||||
} => connect_ssh(cfg, host, *port, user, auth_ref),
|
||||
ConnectionType::Shell {
|
||||
command,
|
||||
sync_args,
|
||||
local_args,
|
||||
..
|
||||
} => {
|
||||
let mut merged_args = sync_args.clone();
|
||||
merged_args.extend(local_args.clone());
|
||||
exec_shell(command, &merged_args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn connect_ssh(
|
||||
cfg: &SshellConfig,
|
||||
host: &str,
|
||||
port: u16,
|
||||
user: &str,
|
||||
auth_ref: &str,
|
||||
) -> Result<()> {
|
||||
if auth_ref.is_empty() {
|
||||
bail!("this connection has no credential; edit it and set password or private key");
|
||||
}
|
||||
match cfg.credential(auth_ref) {
|
||||
Some(CredentialEntry::Password { value, .. }) => {
|
||||
let args = vec![
|
||||
"ssh".to_string(),
|
||||
"-o".to_string(),
|
||||
"StrictHostKeyChecking=accept-new".to_string(),
|
||||
"-p".to_string(),
|
||||
port.to_string(),
|
||||
format!("{user}@{host}"),
|
||||
];
|
||||
run_sshpass(&args, value)
|
||||
}
|
||||
Some(CredentialEntry::PrivateKey { value, .. }) => {
|
||||
let key_content = match value {
|
||||
Some(v) if !v.is_empty() => v,
|
||||
_ => bail!("private key credential {auth_ref} is empty"),
|
||||
};
|
||||
let mut key = NamedTempFile::new()?;
|
||||
key.write_all(key_content.as_bytes())?;
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
key.as_file()
|
||||
.set_permissions(std::fs::Permissions::from_mode(0o600))?;
|
||||
}
|
||||
let status = Command::new("ssh")
|
||||
.arg("-o")
|
||||
.arg("StrictHostKeyChecking=accept-new")
|
||||
.arg("-i")
|
||||
.arg(key.path())
|
||||
.arg("-p")
|
||||
.arg(port.to_string())
|
||||
.arg(format!("{user}@{host}"))
|
||||
.status()?;
|
||||
std::process::exit(status.code().unwrap_or(1));
|
||||
}
|
||||
None => bail!("credential {auth_ref} not found"),
|
||||
}
|
||||
}
|
||||
|
||||
fn run_sshpass(args: &[String], password: &str) -> Result<()> {
|
||||
let status = Command::new("sshpass")
|
||||
.arg("-e")
|
||||
.args(args)
|
||||
.env("SSHPASS", password)
|
||||
.status()
|
||||
.context("failed to run sshpass — is it installed?")?;
|
||||
std::process::exit(status.code().unwrap_or(1));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn exec_shell(command: &str, args: &[String]) -> Result<()> {
|
||||
use std::os::unix::process::CommandExt;
|
||||
let err = Command::new(command).args(args).exec();
|
||||
Err(err).with_context(|| format!("failed to exec {command}"))
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn exec_shell(command: &str, args: &[String]) -> Result<()> {
|
||||
let status = Command::new(command)
|
||||
.args(args)
|
||||
.status()
|
||||
.with_context(|| format!("failed to run {command}"))?;
|
||||
std::process::exit(status.code().unwrap_or(1));
|
||||
}
|
||||
Reference in New Issue
Block a user