Refactor Certificate management
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
name = "bonknet_client"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "A CLI Client for the Bonknet system"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -17,3 +18,5 @@ rmp-serde = "1.1.2"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
uuid = { version = "1.7.0", features = ["serde"] }
|
||||
clap = { version = "4.5.2", features = ["derive"] }
|
||||
thiserror = "1.0.56"
|
||||
|
||||
61
bonknet_client/src/client.rs
Normal file
61
bonknet_client/src/client.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
use std::sync::Arc;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_rustls::{TlsConnector};
|
||||
use tokio_rustls::client::TlsStream;
|
||||
use tokio_rustls::rustls::pki_types::ServerName;
|
||||
use tokio_util::codec::{Framed, LengthDelimitedCodec};
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use thiserror::Error;
|
||||
use tokio_rustls::rustls::ClientConfig;
|
||||
use tracing::{error};
|
||||
use libbonknet::clientmsg::{FromClientCommand, ToClientResponse};
|
||||
|
||||
pub type TransportStream = Framed<TlsStream<TcpStream>, LengthDelimitedCodec>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum SendError {
|
||||
#[error("Failure during serialization of the msg to send")]
|
||||
MsgSerializationFailure(rmp_serde::encode::Error),
|
||||
#[error("Failure during the transport send of the data")]
|
||||
TransportError(std::io::Error),
|
||||
#[error("Empty buffer during reply wait")]
|
||||
EmptyBufferError,
|
||||
#[error("Generic buffer error during response reading")]
|
||||
GenericBufferError(std::io::Error),
|
||||
#[error("Failure during deserialization of the reply msg")]
|
||||
ReplyDeserializationFailure(rmp_serde::decode::Error),
|
||||
}
|
||||
|
||||
pub struct BonkClient {
|
||||
transport: TransportStream,
|
||||
}
|
||||
|
||||
impl BonkClient {
|
||||
pub async fn connect(tlsconfig: ClientConfig, dnsname: &str, port: u16) -> tokio::io::Result<BonkClient> {
|
||||
// Load TLS Config
|
||||
let connector = TlsConnector::from(Arc::new(tlsconfig));
|
||||
let stream = TcpStream::connect(format!("{}:{}", dnsname, port)).await?;
|
||||
let dnsservername = ServerName::try_from(dnsname).unwrap().to_owned();
|
||||
let stream = connector.connect(dnsservername, stream).await?;
|
||||
|
||||
let transport = Framed::new(stream, LengthDelimitedCodec::new());
|
||||
Ok(BonkClient { transport })
|
||||
}
|
||||
|
||||
// TODO: make this private and make single calls for each Bonk interaction?
|
||||
// The main idea is that the messages need to be inside the API and not ouside as elements of it
|
||||
pub async fn send(&mut self, msg: &FromClientCommand) -> Result<ToClientResponse, SendError> {
|
||||
let bmsg = rmp_serde::to_vec(msg).map_err(SendError::MsgSerializationFailure)?;
|
||||
self.transport.send(bmsg.into()).await.map_err(SendError::TransportError)?;
|
||||
match self.transport.next().await {
|
||||
None => Err(SendError::EmptyBufferError),
|
||||
Some(item) => match item {
|
||||
Ok(buf) => {
|
||||
let reply: ToClientResponse = rmp_serde::from_slice(&buf).map_err(SendError::ReplyDeserializationFailure)?;
|
||||
Ok(reply)
|
||||
}
|
||||
Err(e) => Err(SendError::GenericBufferError(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
bonknet_client/src/main.rs
Normal file
64
bonknet_client/src/main.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
mod client;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use clap::{Parser, Subcommand};
|
||||
use libbonknet::cert::*;
|
||||
use tracing::{info};
|
||||
use libbonknet::clientmsg::FromClientCommand;
|
||||
use crate::client::BonkClient;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum Commands {
|
||||
/// connect via ssh to the given remote_id.
|
||||
Ssh {
|
||||
remote_id: String,
|
||||
},
|
||||
/// send a file from source to remote. This command uses scp syntax and must contain wildcards to work (see examples).
|
||||
Scp {
|
||||
remote_id: String,
|
||||
source: PathBuf,
|
||||
dest: PathBuf,
|
||||
},
|
||||
/// get a list of all the servers connected to the broker.
|
||||
Serverlist {
|
||||
pattern: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
// Tracing Subscriber
|
||||
let subscriber = tracing_subscriber::FmtSubscriber::new();
|
||||
tracing::subscriber::set_global_default(subscriber).unwrap();
|
||||
// CLI parsing
|
||||
let cli = Cli::parse();
|
||||
// Load Identity files
|
||||
let client_ident = LeafCertPair::load_from_file("certs_pem/client.pem").unwrap();
|
||||
let broker_root = BrokerRootCerts::load_from_file("certs_pem/broker_root_ca_cert.pem").unwrap();
|
||||
let tlsconfig = client_ident.to_tlsclientconfig(&broker_root);
|
||||
// Execute command
|
||||
match &cli.command {
|
||||
Commands::Ssh { remote_id } => {
|
||||
info!("Run SSH on {remote_id}");
|
||||
unimplemented!()
|
||||
}
|
||||
Commands::Scp { remote_id, source, dest } => {
|
||||
info!("Run SCP on {} moving {} to {}", remote_id, source.display(), dest.display());
|
||||
unimplemented!()
|
||||
}
|
||||
Commands::Serverlist { pattern } => {
|
||||
info!("Run Clientlist with pattern {:?}", pattern);
|
||||
let mut client = BonkClient::connect(tlsconfig, "localhost", 2541).await.unwrap();
|
||||
let reply = client.send(&FromClientCommand::ServerList).await.unwrap();
|
||||
info!("Reply: {:?}", reply);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user