difftreelog
refactor(remowt-ssh) switch to russh
in: trunk
2 files changed
cmds/remowt-ssh/Cargo.tomldiffbeforeafterboth--- a/cmds/remowt-ssh/Cargo.toml
+++ b/cmds/remowt-ssh/Cargo.toml
@@ -4,17 +4,25 @@
edition = "2021"
[dependencies]
-clap = { version = "4.5.16", features = ["derive"] }
-openssh = { version = "0.11.0", features = ["native-mux"] }
-tracing-subscriber = "0.3.18"
+clap = { workspace = true, features = ["derive"] }
+openssh = { workspace = true, features = ["native-mux"] }
+tracing-subscriber.workspace = true
bifrostlink.workspace = true
-remowt-link-shared = { version = "0.1.0", path = "../../crates/remowt-link-shared" }
-tokio = { version = "1.39.3", features = ["macros"] }
-anyhow = "1.0.86"
+remowt-link-shared.workspace = true
+remowt-client.workspace = true
+tokio = { workspace = true, features = ["macros", "fs", "net", "io-util", "rt", "signal"] }
+nix = { workspace = true, features = ["term"] }
+anyhow.workspace = true
bifrostlink-ports.workspace = true
-uuid = { version = "1.10.0", features = ["v4"] }
-tempdir = "0.3.7"
-russh = { git = "https://github.com/Eugeny/russh/" }
-russh-config = { git = "https://github.com/Eugeny/russh/" }
-russh-keys = { git = "https://github.com/Eugeny/russh/" }
-async-trait = "0.1.81"
+uuid = { workspace = true, features = ["v4"] }
+tempdir.workspace = true
+async-trait.workspace = true
+bytes.workspace = true
+tokio-stream.workspace = true
+tracing.workspace = true
+thiserror = "2.0.18"
+serde_json.workspace = true
+serde.workspace = true
+ui-prompt.workspace = true
+russh.workspace = true
+russh-config.workspace = true
cmds/remowt-ssh/src/main.rsdiffbeforeafterboth1use std::borrow::Cow;2use std::ffi::OsString;3use std::os::unix::ffi::OsStringExt;4use std::path::PathBuf;5use std::sync::Arc;67use anyhow::{bail, ensure};8use async_trait::async_trait;9use bifrostlink::Rpc;10use clap::Parser;11use remowt_link_shared::Address;12use russh::client::{connect, Config, Handler, Session};13use tempdir::TempDir;14use tokio::io::{AsyncReadExt, AsyncWriteExt};15use tokio::net::UnixSocket;1617#[derive(Parser)]18struct Opts {19 host: String,20}2122struct MyHandler {23 host: String,24 port: u16,25}26#[async_trait]27impl Handler for MyHandler {28 type Error = russh::Error;29 async fn check_server_key(30 &mut self,31 server_public_key: &russh_keys::key::PublicKey,32 ) -> Result<bool, Self::Error> {33 Ok(russh_keys::check_known_hosts(34 &self.host,35 self.port,36 &server_public_key,37 )?)38 }39}4041#[tokio::main(flavor = "current_thread")]42async fn main() -> anyhow::Result<()> {43 let rpc = Rpc::<Address, remowt_link_shared::Error>::new(Address::User);44 tracing_subscriber::fmt::init();45 let opts = Opts::parse();4647 let conf = dbg!(russh_config::parse_home(&opts.host)?);48 println!("connect");49 let mut sess = connect(50 Arc::new(Config {51 ..Default::default()52 }),53 dbg!((conf.host_name.clone(), conf.port)),54 MyHandler {55 host: conf.host_name,56 port: conf.port,57 },58 )59 .await?;60 println!("agent");61 let mut agent = russh_keys::agent::client::AgentClient::connect_env().await?;62 for ele in agent.request_identities().await? {63 let (_agent, res) = sess.authenticate_future(conf.user.clone(), ele, agent).await;64 agent = _agent;65 if res? {66 break;67 }68 }69 // let sess = Session::connect(opts.host, openssh::KnownHosts::Strict).await?;7071 let socket = UnixSocket::new_stream()?;7273 println!("mktemp");74 let mut cmd_chan = sess.channel_open_session().await?;75 cmd_chan76 .exec(true, "mktemp -d remowt.XXXXXXXXXXXX --tmpdir")77 .await?;78 let mut stdout = vec![];79 loop {80 let Some(msg) = cmd_chan.wait().await else {81 bail!("unexpected channel end");82 };83 match msg {84 russh::ChannelMsg::Data { data } => stdout.extend(data.as_ref()),85 russh::ChannelMsg::ExitStatus { exit_status } => {86 if exit_status != 0 {87 bail!("mktemp failed");88 }89 break;90 }91 _ => {}92 }93 }9495 ensure!(stdout.ends_with(b"\n"));96 stdout.pop();9798 // Remote host is not neccessary linux, openssh crate makes incorrect assumptions here.99 // TODO: Remove on local close.100 let remote_dir = PathBuf::from(OsString::from_vec(stdout));101 let remote_socket = remote_dir.join("primary.sock");102103 let local_dir = TempDir::new("remowt")?;104 let local_socket = local_dir.path().join("primary.sock");105106 println!("listen");107 socket.bind(&local_socket)?;108 let listener = socket.listen(1)?;109110 eprintln!("forward socket");111112 let mut sock = sess113 .channel_open_direct_streamlocal(dbg!(remote_socket.to_str().expect("path is utf-8")))114 .await?;115116 eprintln!("wait");117 while let Some(v) = sock.wait().await {118 dbg!(v);119 }120121 eprintln!("spawn agent");122123 // let _agent = sess124 // .command("/home/lach/.remowt/remowt-agent")125 // .arg("agent-real")126 // .arg("--path")127 // .arg(remote_socket.to_str().expect("path is utf-8"))128 // .spawn()129 // .await?;130 //131 // let (mut conn, _) = listener.accept().await?;132 // let mut buf = [0u8; 13];133 // conn.read_exact(&mut buf).await?;134 // assert_eq!(&buf, b"REMOWT_HELLO\0");135 // conn.write_all(b"REMOWT_EHLO\0").await?;136 //137 // println!("handshake complete!");138139 Ok(())140}