ssh_utils_lib/ssh/
key_session.rs1use std::sync::Arc;
2use anyhow::Result;
3use async_trait::async_trait;
4use russh::keys::*;
5use russh::*;
6use tokio::net::ToSocketAddrs;
7use super::common::{default_ssh_config, SshChannel};
8use super::ssh_session::{AuthMethod, SshSession};
9
10pub struct Client {}
11
12#[async_trait]
16impl client::Handler for Client {
17 type Error = russh::Error;
18
19 async fn check_server_key(
20 &mut self,
21 _server_public_key: &key::PublicKey,
22 ) -> Result<bool, Self::Error> {
23 Ok(true)
24 }
25}
26
27pub struct KeySession {
31 session: client::Handle<Client>,
32}
33
34#[async_trait::async_trait]
35impl SshSession for KeySession {
36 async fn connect<A: ToSocketAddrs + Send>(
37 user: impl Into<String> + Send,
38 auth: impl Into<AuthMethod> + Send,
39 addrs: A,
40 ) -> Result<Self> {
41 let auth = auth.into();
42 let key_pair = match auth {
43 AuthMethod::Key(path) => path,
44 AuthMethod::Password(_) => anyhow::bail!("KeySession only supports key authentication"),
45 };
46
47 let config = default_ssh_config();
50
51 let config = Arc::new(config);
52 let sh = Client {};
53
54 let mut session = client::connect(config, addrs, sh).await?;
55
56 let auth_res = session
58 .authenticate_publickey(user, Arc::new(key_pair))
59 .await?;
60
61 if !auth_res {
62 anyhow::bail!("public key authentication failed");
63 }
64
65 Ok(Self { session })
66 }
67
68 async fn call(&mut self, command: &str) -> Result<u32> {
69 let channel = self.session.channel_open_session().await?;
70 let mut ssh_channel = SshChannel::new(channel).await?;
71 ssh_channel.call(command).await
72 }
73
74 async fn close(&mut self) -> Result<()> {
75 self.session
76 .disconnect(Disconnect::ByApplication, "", "English")
77 .await?;
78 Ok(())
79 }
80}