From 8459c38499e751669d0373735e47d1a44b770410 Mon Sep 17 00:00:00 2001 From: Jean-Gabriel Gill-Couture Date: Mon, 14 Oct 2024 07:53:02 -0400 Subject: [PATCH] wip(opnsense-config): It compiles now, still have to test it --- harmony-rs/opnsense-config/src/config.rs | 64 ++++++++++++++++++++---- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/harmony-rs/opnsense-config/src/config.rs b/harmony-rs/opnsense-config/src/config.rs index 99c8a45..205b7d3 100644 --- a/harmony-rs/opnsense-config/src/config.rs +++ b/harmony-rs/opnsense-config/src/config.rs @@ -1,27 +1,68 @@ use crate::error::Error; use crate::modules::opnsense::OPNsense; +use async_trait::async_trait; use russh::client::{Config as SshConfig, Handler}; -use std::sync::Arc; use russh_keys::key; +use std::{fmt::Write as _, sync::Arc}; +use tokio::io::AsyncWriteExt; + +struct Client {} + +// More SSH event handlers +// can be defined in this trait +// In this example, we're only using Channel, so these aren't needed. +#[async_trait] +impl Handler for Client { + type Error = Error; + + async fn check_server_key( + &mut self, + _server_public_key: &key::PublicKey, + ) -> Result { + Ok(true) + } +} pub struct Config { opnsense: OPNsense, ssh_config: Arc, host: String, username: String, + key: Arc, } impl Config { pub async fn new(host: &str, username: &str, key_path: &str) -> Result { let key = russh_keys::load_secret_key(key_path, None).expect("Secret key failed loading"); + let key = Arc::new(key); let config = SshConfig::default(); let config = Arc::new(config); - let mut ssh = russh::client::connect(config.clone(), host, Handler).await?; - ssh.authenticate_publickey(username, key).await?; + let mut ssh = russh::client::connect(config.clone(), host, Client {}).await?; + ssh.authenticate_publickey(username, key.clone()).await?; - let (xml, _) = ssh.exec(true, "cat /conf/config.xml").await?; - let xml = String::from_utf8(xml).map_err(|e| Error::Config(e.to_string()))?; + let mut channel = ssh.channel_open_session().await?; + + channel.exec(true, "cat /conf/config.xml").await?; + let mut code; + let mut output = String::new(); + loop { + let Some(msg) = channel.wait().await else { + break; + }; + + match msg { + russh::ChannelMsg::Data { ref data } => { + write!(&mut output, "{:?}", data); + println!("Got data {output}"); + } + russh::ChannelMsg::ExitStatus { exit_status } => { + code = Some(exit_status); + } + _ => todo!(), + } + } + let xml = output; let opnsense = yaserde::de::from_str(&xml).map_err(|e| Error::Xml(e.to_string()))?; @@ -30,6 +71,7 @@ impl Config { ssh_config: config, host: host.to_string(), username: username.to_string(), + key, }) } @@ -44,12 +86,14 @@ impl Config { pub async fn save(&self) -> Result<(), Error> { let xml = yaserde::ser::to_string(&self.opnsense).map_err(|e| Error::Xml(e.to_string()))?; - let mut ssh = russh::client::connect(self.ssh_config.clone(), &self.host, Handler).await?; - ssh.authenticate_publickey(&self.username, key).await?; + let mut ssh = + russh::client::connect(self.ssh_config.clone(), &self.host, Client {}).await?; + ssh.authenticate_publickey(&self.username, self.key.clone()).await?; + todo!("Writing config file to remote host {xml}"); - ssh.exec(true, &format!("echo '{}' > /conf/config.xml", xml)) - .await?; + // ssh.exec(true, &format!("echo '{}' > /conf/config.xml", xml)) + // .await?; - Ok(()) + // Ok(()) } }