use crate::codec::{read_message, write_message, ReadMessage, WriteMessage};
use ssh_key::{PrivateKey, PublicKey, Signature};
use std::io::{Read, Write};
use std::os::unix::net::UnixStream;
use std::path::Path;
mod codec;
mod error;
pub use self::error::Error;
pub use self::error::Result;
pub trait ReadWrite: Read + Write {}
pub struct Client {
socket: Box<dyn ReadWrite>,
}
impl ReadWrite for UnixStream {}
impl Client {
pub fn connect(path: &Path) -> Result<Client> {
let socket = Box::new(UnixStream::connect(path)?);
Ok(Client { socket })
}
pub fn with_read_write(read_write: Box<dyn ReadWrite>) -> Client {
Client { socket: read_write }
}
pub fn list_identities(&mut self) -> Result<Vec<PublicKey>> {
write_message(&mut self.socket, WriteMessage::RequestIdentities)?;
match read_message(&mut self.socket)? {
ReadMessage::Identities(identities) => Ok(identities),
_ => Err(Error::UnknownMessageType),
}
}
pub fn add_identity(&mut self, key: &PrivateKey) -> Result<()> {
write_message(&mut self.socket, WriteMessage::AddIdentity(key))?;
self.expect_success()
}
pub fn remove_identity(&mut self, key: &PrivateKey) -> Result<()> {
write_message(&mut self.socket, WriteMessage::RemoveIdentity(key))?;
self.expect_success()
}
pub fn remove_all_identities(&mut self) -> Result<()> {
write_message(&mut self.socket, WriteMessage::RemoveAllIdentities)?;
self.expect_success()
}
pub fn sign(&mut self, key: &PublicKey, data: &[u8]) -> Result<Signature> {
write_message(&mut self.socket, WriteMessage::Sign(key, data))?;
match read_message(&mut self.socket)? {
ReadMessage::Signature(sig) => Ok(sig),
ReadMessage::Failure => Err(Error::RemoteFailure),
_ => Err(Error::UnknownMessageType),
}
}
fn expect_success(&mut self) -> Result<()> {
let response = read_message(&mut self.socket)?;
match response {
ReadMessage::Success => Ok(()),
ReadMessage::Failure => Err(Error::RemoteFailure),
_ => Err(Error::InvalidData(Some("Unexpected response".to_string()))),
}
}
}