diff --git a/Cargo.lock b/Cargo.lock index 9963585..98d6363 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1713,7 +1713,7 @@ dependencies = [ [[package]] name = "iroh-ssh" -version = "0.2.3" +version = "0.2.4" dependencies = [ "anyhow", "clap", @@ -1727,6 +1727,7 @@ dependencies = [ "tokio-stream", "tracing", "tracing-subscriber", + "whoami", "z32", ] @@ -3796,6 +3797,12 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -3930,6 +3937,17 @@ dependencies = [ "rustix 0.38.44", ] +[[package]] +name = "whoami" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +dependencies = [ + "redox_syscall", + "wasite", + "web-sys", +] + [[package]] name = "widestring" version = "1.2.0" diff --git a/Cargo.toml b/Cargo.toml index f80c43e..5dd4e7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/rustonbsd/iroh-ssh" readme = "README.md" keywords = ["networking"] categories = ["network-programming"] -version = "0.2.3" +version = "0.2.4" edition = "2024" [dependencies] @@ -26,6 +26,7 @@ tokio = { version = "1", features = [ ] } clap = { version = "4.5.41", features = ["derive"] } homedir = "0.3.6" +whoami = "1.6.0" z32 = "1.3" runas = "1.2.0" tempfile = "3.20.0" diff --git a/README.md b/README.md index 669ebe5..f3d13c4 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Download and setup the binary automatically for your operating system from [GitH Linux ```bash # Linux -wget https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.3/iroh-ssh.linux +wget https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.4/iroh-ssh.linux chmod +x iroh-ssh.linux sudo mv iroh-ssh.linux /usr/local/bin/iroh-ssh ``` @@ -44,7 +44,7 @@ sudo mv iroh-ssh.linux /usr/local/bin/iroh-ssh macOS ```bash # macOS arm -curl -LJO https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.3/iroh-ssh.macos +curl -LJO https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.4/iroh-ssh.macos chmod +x iroh-ssh.macos sudo mv iroh-ssh.macos /usr/local/bin/iroh-ssh ``` @@ -52,7 +52,7 @@ sudo mv iroh-ssh.macos /usr/local/bin/iroh-ssh Windows ```bash # Windows x86 64bit -curl -L -o iroh-ssh.exe https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.3/iroh-ssh.exe +curl -L -o iroh-ssh.exe https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.4/iroh-ssh.exe mkdir %LOCALAPPDATA%\iroh-ssh move iroh-ssh.exe %LOCALAPPDATA%\iroh-ssh\ setx PATH "%PATH%;%LOCALAPPDATA%\iroh-ssh" @@ -137,15 +137,14 @@ Display its Node ID and share it to allow connection > iroh-ssh info Your iroh-ssh nodeid: 38b7dc10df96005255c3beaeaeef6cfebd88344aa8c85e1dbfc1ad5e50f372ac - iroh-ssh version 0.2.2 + iroh-ssh version 0.2.4 https://github.com/rustonbsd/iroh-ssh - run 'iroh-ssh server --persist' to start the server with persistent keys - run 'iroh-ssh server' to start the server with ephemeral keys - run 'iroh-ssh service install' to start the server as a service (always uses persistent keys) - - Your iroh-ssh nodeid: + Your server iroh-ssh nodeid: iroh-ssh my-user@38b7dc10df96005255c3beaeaeef6cfebd88344aa8c85e1dbfc1ad5e50f372ac + + Your service iroh-ssh nodeid: + iroh-ssh my-user@4fjeeiui4jdm96005255c3begj389xk3aeaeef6cfebd88344aa8c85e1dbfc1ad ``` --- @@ -155,15 +154,15 @@ Display its Node ID and share it to allow connection ## How It Works ``` -┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ ┌─────────────┐ +┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ ┌─────────────┐ │ iroh-ssh │───▶│ internal TCP │───▶│ QUIC Tunnel │───▶│ iroh-ssh │ -│ (your machine) │ Listener │ │ (P2P Network) │ │ server │ -└─────────────┘ | (your machine) └─────────────────┘ └─────────────┘ +│ (your machine) │ Listener │ │ (P2P Network) │ │ server │ +└─────────────┘ | (your machine) └─────────────────┘ └─────────────┘ └──────────────┘ │ ▲ │ ▼ │ ▼ ┌──────────────┐ ┌─────────────┐ - ⦜ -- ▶ │ run: ssh │ │ SSH Server │ + ⦜ -- ▶ │ run: ssh │ │ SSH Server │ │ user@localhost │ (port 22) │ └──────────────┘ └─────────────┘ ``` diff --git a/src/api.rs b/src/api.rs index 459e5ff..d68422f 100644 --- a/src/api.rs +++ b/src/api.rs @@ -7,29 +7,48 @@ use iroh::{NodeId, SecretKey}; use crate::{dot_ssh, IrohSsh}; pub async fn info_mode() -> anyhow::Result<()> { - let key = dot_ssh(&SecretKey::generate(rand::rngs::OsRng), false); - if key.is_err() { - println!("No keys found, run 'iroh-ssh server --persist' or '-p' to create it"); + let server_key = match dot_ssh(&SecretKey::generate(rand::rngs::OsRng), false,false) { + Ok(key) => Some(key), + Err(_) => None, + }; + let service_key = match dot_ssh(&SecretKey::generate(rand::rngs::OsRng), false,true) { + Ok(key) => Some(key), + Err(_) => None, + }; + + if server_key.is_none() && service_key.is_none() { + println!("No keys found, run for server or service:\n 'iroh-ssh server --persist' or '-p' to create it"); println!(); println!("(if an iroh-ssh instance is currently running, it is using ephemeral keys)"); bail!("No keys found") } - let key = key.unwrap(); - let node_id = key.public(); - println!("Your iroh-ssh nodeid: {}", node_id.to_string()); - println!("iroh-ssh version {}", env!("CARGO_PKG_VERSION")); println!("https://github.com/rustonbsd/iroh-ssh"); println!(""); - println!("run 'iroh-ssh server --persist' to start the server with persistent keys"); - println!("run 'iroh-ssh server' to start the server with ephemeral keys"); - println!( - "run 'iroh-ssh service install' to copy the binary, install the service and start the server (always uses persistent keys)" - ); - println!(""); - println!("Your iroh-ssh nodeid:"); - println!(" iroh-ssh my-user@{}\n\n", key.public().to_string()); + + if server_key.is_none() && service_key.is_none() { + println!("run 'iroh-ssh server --persist' to start the server with persistent keys"); + println!("run 'iroh-ssh server' to start the server with ephemeral keys"); + println!( + "run 'iroh-ssh service install' to copy the binary, install the service and start the server (always uses persistent keys)" + ); + } + + if let Some(key) = server_key { + println!(""); + println!("Your server iroh-ssh nodeid:"); + println!(" iroh-ssh {}@{}", whoami::username(), key.clone().public().to_string()); + println!(""); + } + + if let Some(key) = service_key { + println!(""); + println!("Your service iroh-ssh nodeid:"); + println!(" iroh-ssh {}@{}", whoami::username(), key.clone().public().to_string()); + println!(""); + } + Ok(()) } @@ -56,12 +75,12 @@ pub mod service { pub async fn server_mode(ssh_port: u16, persist: bool) -> anyhow::Result<()> { let mut iroh_ssh_builder = IrohSsh::new().accept_incoming(true).accept_port(ssh_port); if persist { - iroh_ssh_builder = iroh_ssh_builder.dot_ssh_integration(true); + iroh_ssh_builder = iroh_ssh_builder.dot_ssh_integration(true,false); } let iroh_ssh = iroh_ssh_builder.build().await?; println!("Connect to this this machine:"); - println!("\n iroh-ssh my-user@{}\n", iroh_ssh.node_id()); + println!("\n iroh-ssh {}@{}\n", whoami::username(), iroh_ssh.node_id()); if persist { let distro_home = my_home()?.ok_or_else(|| anyhow::anyhow!("home directory not found"))?; diff --git a/src/ssh.rs b/src/ssh.rs index 140d48a..b276ad5 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -36,8 +36,8 @@ impl Builder { self } - pub fn dot_ssh_integration(mut self, persist: bool) -> Self { - if let Ok(secret_key) = dot_ssh(&SecretKey::from_bytes(&self.secret_key), persist) { + pub fn dot_ssh_integration(mut self, persist: bool, service: bool) -> Self { + if let Ok(secret_key) = dot_ssh(&SecretKey::from_bytes(&self.secret_key), persist, service) { self.secret_key = secret_key.to_bytes(); } self @@ -213,7 +213,9 @@ impl ProtocolHandler for IrohSsh { } } -pub fn dot_ssh(default_secret_key: &SecretKey, persist: bool) -> anyhow::Result { + + +pub fn dot_ssh(default_secret_key: &SecretKey, persist: bool, service: bool) -> anyhow::Result { let distro_home = my_home()?.ok_or_else(|| anyhow::anyhow!("home directory not found"))?; #[allow(unused_mut)] let mut ssh_dir = distro_home.join(".ssh"); @@ -221,17 +223,15 @@ pub fn dot_ssh(default_secret_key: &SecretKey, persist: bool) -> anyhow::Result< // For now linux services are installed as "sudo'er" so // we need to use the root .ssh directory #[cfg(target_os = "linux")] - if !ssh_dir.join("irohssh_ed25519.pub").exists() { + if service { ssh_dir = std::path::PathBuf::from("/root/.ssh"); - println!("[INFO] using linux service ssh_dir: {}", ssh_dir.display()); } // Weird windows System service profile location: // "C:\WINDOWS\system32\config\systemprofile\.ssh" #[cfg(target_os = "windows")] - if !ssh_dir.join("irohssh_ed25519.pub").exists() { + if service { ssh_dir = std::path::PathBuf::from(r#"C:\WINDOWS\system32\config\systemprofile\.ssh"#); - println!("[INFO] using windows service ssh_dir: {}", ssh_dir.display()); } let pub_key = ssh_dir.join("irohssh_ed25519.pub"); @@ -244,7 +244,7 @@ pub fn dot_ssh(default_secret_key: &SecretKey, persist: bool) -> anyhow::Result< (false, true) => { std::fs::create_dir_all(&ssh_dir)?; println!("[INFO] created .ssh folder: {}", ssh_dir.display()); - dot_ssh(default_secret_key, persist) + dot_ssh(default_secret_key, persist, service) } (true, true) => { // check pub and priv key already exists