use anyhow::Result; use crate::{ platform::{ Platform, PlatformKey }, config::{ ConfigManager, Host } }; use dialoguer::{ Select, FuzzySelect, Input, theme::ColorfulTheme }; use ssh_key::PrivateKey; use std::fs; use std::path::PathBuf; pub fn get_host(config: &mut ConfigManager) -> Result { if config.configs.len() < 1 { let _ = config.new_host()?; } let hosts = config.configs.to_owned(); let hosts: Vec = hosts.into_iter().collect(); let theme = ColorfulTheme::default(); let mut select = Select::with_theme(&theme); select.with_prompt("Host") .items(hosts.as_slice()) .item("New host definition...") .default(0); Ok({ let c = select.interact()?; if c == hosts.len() { config.new_host()? } else { hosts.get(c).unwrap().to_owned() } }) } pub fn get_platform() -> Result { let platforms = Platform::all(); let c = Select::with_theme(&ColorfulTheme::default()) .with_prompt("Platform") .items(platforms.as_slice()) .default(0) .interact()?; Ok(platforms.get(c).unwrap().to_owned()) } pub fn get_key(config: &ConfigManager, platform: Platform) -> Result { let keys: Vec = platform.get_keys(config); let c = FuzzySelect::with_theme(&ColorfulTheme::default()) .with_prompt("Key") .items(keys.as_slice()) .item("Other...") .default(0) .interact()?; match c == keys.len() { true => get_custom_key(), false => Ok(keys.get(c).unwrap().to_owned()), } } pub fn get_custom_key() -> Result { let theme = ColorfulTheme::default(); let mut input = Input::with_theme(&theme); input.with_prompt("Path").with_initial_text(dirs::home_dir().unwrap().join(".ssh/").to_string_lossy().to_string()); Ok(loop { let buffer: String = input.interact_text()?; if fs::try_exists(buffer.to_owned()).unwrap_or(false) { break match PrivateKey::read_openssh_file(&PathBuf::from(buffer.to_owned())) { Ok(p) => PlatformKey { file: buffer.to_owned(), display: format!("{}: {}", p.fingerprint(ssh_key::HashAlg::Sha256), buffer) }, Err(_) => { println!("File is not SSH private key"); continue; }, } } else { println!("File doesn't exist") } }) } fn edit_temp(temp: &mktemp::Temp) -> Result<()> { let editor = std::env::var("EDITOR").expect("EDITOR is not set"); std::process::Command::new(editor) .arg(&temp.to_str().unwrap()) .spawn()?.wait()?; Ok(()) } pub fn edit_temp_from_string(data: &String) -> Result { let t = mktemp::Temp::new_file()?; fs::write(&t, data)?; edit_temp(&t)?; Ok(t) } pub fn edit_temp_from_file(file: &String) -> Result { let t = mktemp::Temp::new_file()?; fs::copy(file, &t)?; edit_temp(&t)?; Ok(t) }