use std::io::{Read, Write};
use byteorder::{BigEndian, ByteOrder};
use ssh_encoding::{Decode, Encode};
use ssh_key::Signature;
use crate::{
error::AgentError,
proto::{
AddIdentity, AddIdentityConstrained, AddSmartcardKeyConstrained, Extension, Identity,
ProtoError, RemoveIdentity, Request, Response, SignRequest, SmartcardKey,
},
};
#[derive(Debug)]
pub struct Client<S: Read + Write> {
stream: S,
}
impl<S: Read + Write> Client<S> {
pub fn new(stream: S) -> Self {
Self { stream }
}
pub fn into_inner(self) -> S {
self.stream
}
fn handle(&mut self, request: Request) -> Result<Response, ProtoError> {
let mut bytes = Vec::new();
let len = request.encoded_len()? as u32;
len.encode(&mut bytes)?;
request.encode(&mut bytes)?;
self.stream.write_all(&bytes)?;
let mut len: [u8; 4] = [0; 4];
self.stream.read_exact(&mut len[..])?;
let len = BigEndian::read_u32(&len) as usize;
bytes.resize(len, 0);
self.stream.read_exact(&mut bytes)?;
Response::decode(&mut &bytes[..])
}
pub fn request_identities(&mut self) -> Result<Vec<Identity>, AgentError> {
if let Response::IdentitiesAnswer(identities) = self.handle(Request::RequestIdentities)? {
Ok(identities)
} else {
Err(ProtoError::UnexpectedResponse.into())
}
}
pub fn sign(&mut self, request: SignRequest) -> Result<Signature, AgentError> {
if let Response::SignResponse(response) = self.handle(Request::SignRequest(request))? {
Ok(response)
} else {
Err(ProtoError::UnexpectedResponse.into())
}
}
pub fn add_identity(&mut self, identity: AddIdentity) -> Result<(), AgentError> {
if let Response::Success = self.handle(Request::AddIdentity(identity))? {
Ok(())
} else {
Err(ProtoError::UnexpectedResponse.into())
}
}
pub fn add_identity_constrained(
&mut self,
identity: AddIdentityConstrained,
) -> Result<(), AgentError> {
if let Response::Success = self.handle(Request::AddIdConstrained(identity))? {
Ok(())
} else {
Err(ProtoError::UnexpectedResponse.into())
}
}
pub fn remove_identity(&mut self, identity: RemoveIdentity) -> Result<(), AgentError> {
if let Response::Success = self.handle(Request::RemoveIdentity(identity))? {
Ok(())
} else {
Err(ProtoError::UnexpectedResponse.into())
}
}
pub fn remove_all_identities(&mut self) -> Result<(), AgentError> {
if let Response::Success = self.handle(Request::RemoveAllIdentities)? {
Ok(())
} else {
Err(ProtoError::UnexpectedResponse.into())
}
}
pub fn add_smartcard_key(&mut self, key: SmartcardKey) -> Result<(), AgentError> {
if let Response::Success = self.handle(Request::AddSmartcardKey(key))? {
Ok(())
} else {
Err(ProtoError::UnexpectedResponse.into())
}
}
pub fn add_smartcard_key_constrained(
&mut self,
key: AddSmartcardKeyConstrained,
) -> Result<(), AgentError> {
if let Response::Success = self.handle(Request::AddSmartcardKeyConstrained(key))? {
Ok(())
} else {
Err(ProtoError::UnexpectedResponse.into())
}
}
pub fn remove_smartcard_key(&mut self, key: SmartcardKey) -> Result<(), AgentError> {
if let Response::Success = self.handle(Request::RemoveSmartcardKey(key))? {
Ok(())
} else {
Err(ProtoError::UnexpectedResponse.into())
}
}
pub fn lock(&mut self, key: String) -> Result<(), AgentError> {
if let Response::Success = self.handle(Request::Lock(key))? {
Ok(())
} else {
Err(ProtoError::UnexpectedResponse.into())
}
}
pub fn unlock(&mut self, key: String) -> Result<(), AgentError> {
if let Response::Success = self.handle(Request::Unlock(key))? {
Ok(())
} else {
Err(ProtoError::UnexpectedResponse.into())
}
}
pub fn extension(&mut self, extension: Extension) -> Result<Option<Extension>, AgentError> {
match self.handle(Request::Extension(extension))? {
Response::Success => Ok(None),
Response::ExtensionResponse(response) => Ok(Some(response)),
_ => Err(ProtoError::UnexpectedResponse.into()),
}
}
}