ssh_agent_lib/
blocking.rs1use std::io::{Read, Write};
27
28use byteorder::{BigEndian, ByteOrder};
29use ssh_encoding::{Decode, Encode};
30use ssh_key::Signature;
31
32use crate::{
33 error::AgentError,
34 proto::{
35 AddIdentity, AddIdentityConstrained, AddSmartcardKeyConstrained, Extension, Identity,
36 ProtoError, RemoveIdentity, Request, Response, SignRequest, SmartcardKey,
37 },
38};
39
40#[derive(Debug)]
42pub struct Client<S: Read + Write> {
43 stream: S,
44}
45
46impl<S: Read + Write> Client<S> {
47 pub fn new(stream: S) -> Self {
49 Self { stream }
50 }
51
52 pub fn into_inner(self) -> S {
54 self.stream
55 }
56
57 fn handle(&mut self, request: Request) -> Result<Response, ProtoError> {
58 let mut bytes = Vec::new();
60 let len = request.encoded_len()? as u32;
61 len.encode(&mut bytes)?;
62 request.encode(&mut bytes)?;
63 self.stream.write_all(&bytes)?;
64
65 let mut len: [u8; 4] = [0; 4];
67 self.stream.read_exact(&mut len[..])?;
68 let len = BigEndian::read_u32(&len) as usize;
69 bytes.resize(len, 0);
70 self.stream.read_exact(&mut bytes)?;
71
72 Response::decode(&mut &bytes[..])
73 }
74
75 pub fn request_identities(&mut self) -> Result<Vec<Identity>, AgentError> {
77 if let Response::IdentitiesAnswer(identities) = self.handle(Request::RequestIdentities)? {
78 Ok(identities)
79 } else {
80 Err(ProtoError::UnexpectedResponse.into())
81 }
82 }
83
84 pub fn sign(&mut self, request: SignRequest) -> Result<Signature, AgentError> {
86 if let Response::SignResponse(response) = self.handle(Request::SignRequest(request))? {
87 Ok(response)
88 } else {
89 Err(ProtoError::UnexpectedResponse.into())
90 }
91 }
92
93 pub fn add_identity(&mut self, identity: AddIdentity) -> Result<(), AgentError> {
95 if let Response::Success = self.handle(Request::AddIdentity(identity))? {
96 Ok(())
97 } else {
98 Err(ProtoError::UnexpectedResponse.into())
99 }
100 }
101
102 pub fn add_identity_constrained(
104 &mut self,
105 identity: AddIdentityConstrained,
106 ) -> Result<(), AgentError> {
107 if let Response::Success = self.handle(Request::AddIdConstrained(identity))? {
108 Ok(())
109 } else {
110 Err(ProtoError::UnexpectedResponse.into())
111 }
112 }
113
114 pub fn remove_identity(&mut self, identity: RemoveIdentity) -> Result<(), AgentError> {
116 if let Response::Success = self.handle(Request::RemoveIdentity(identity))? {
117 Ok(())
118 } else {
119 Err(ProtoError::UnexpectedResponse.into())
120 }
121 }
122
123 pub fn remove_all_identities(&mut self) -> Result<(), AgentError> {
125 if let Response::Success = self.handle(Request::RemoveAllIdentities)? {
126 Ok(())
127 } else {
128 Err(ProtoError::UnexpectedResponse.into())
129 }
130 }
131
132 pub fn add_smartcard_key(&mut self, key: SmartcardKey) -> Result<(), AgentError> {
134 if let Response::Success = self.handle(Request::AddSmartcardKey(key))? {
135 Ok(())
136 } else {
137 Err(ProtoError::UnexpectedResponse.into())
138 }
139 }
140
141 pub fn add_smartcard_key_constrained(
143 &mut self,
144 key: AddSmartcardKeyConstrained,
145 ) -> Result<(), AgentError> {
146 if let Response::Success = self.handle(Request::AddSmartcardKeyConstrained(key))? {
147 Ok(())
148 } else {
149 Err(ProtoError::UnexpectedResponse.into())
150 }
151 }
152
153 pub fn remove_smartcard_key(&mut self, key: SmartcardKey) -> Result<(), AgentError> {
155 if let Response::Success = self.handle(Request::RemoveSmartcardKey(key))? {
156 Ok(())
157 } else {
158 Err(ProtoError::UnexpectedResponse.into())
159 }
160 }
161
162 pub fn lock(&mut self, key: String) -> Result<(), AgentError> {
164 if let Response::Success = self.handle(Request::Lock(key))? {
165 Ok(())
166 } else {
167 Err(ProtoError::UnexpectedResponse.into())
168 }
169 }
170
171 pub fn unlock(&mut self, key: String) -> Result<(), AgentError> {
173 if let Response::Success = self.handle(Request::Unlock(key))? {
174 Ok(())
175 } else {
176 Err(ProtoError::UnexpectedResponse.into())
177 }
178 }
179
180 pub fn extension(&mut self, extension: Extension) -> Result<Option<Extension>, AgentError> {
182 match self.handle(Request::Extension(extension))? {
183 Response::Success => Ok(None),
184 Response::ExtensionResponse(response) => Ok(Some(response)),
185 _ => Err(ProtoError::UnexpectedResponse.into()),
186 }
187 }
188}