ssh_agent_client_rs/
lib.rs1use crate::codec::{read_message, write_message, ReadMessage, WriteMessage};
23#[cfg(target_family = "windows")]
24use interprocess::os::windows::named_pipe::{pipe_mode, DuplexPipeStream};
25use ssh_key::{PrivateKey, PublicKey, Signature};
26use std::io::{Read, Write};
27#[cfg(target_family = "unix")]
28use std::os::unix::net::UnixStream;
29use std::path::Path;
30
31mod codec;
32mod error;
33
34pub use self::error::Error;
35pub use self::error::Result;
36
37pub trait ReadWrite: Read + Write {}
39
40pub struct Client {
43 socket: Box<dyn ReadWrite>,
44}
45
46impl<T> ReadWrite for T where T: Read + Write {}
47
48impl Client {
49 #[cfg(target_family = "unix")]
51 pub fn connect(path: &Path) -> Result<Client> {
52 let socket = Box::new(UnixStream::connect(path)?);
53 Ok(Client { socket })
54 }
55
56 #[cfg(target_family = "windows")]
59 pub fn connect(path: &Path) -> Result<Client> {
60 let pipe = DuplexPipeStream::<pipe_mode::Bytes>::connect_by_path(path)?;
61 Ok(Client {
62 socket: Box::new(pipe),
63 })
64 }
65
66 pub fn with_read_write(read_write: Box<dyn ReadWrite>) -> Client {
69 Client { socket: read_write }
70 }
71
72 pub fn list_identities(&mut self) -> Result<Vec<PublicKey>> {
74 write_message(&mut self.socket, WriteMessage::RequestIdentities)?;
75 match read_message(&mut self.socket)? {
76 ReadMessage::Identities(identities) => Ok(identities),
77 m => Err(unexpected_response(m)),
78 }
79 }
80
81 pub fn add_identity(&mut self, key: &PrivateKey) -> Result<()> {
83 write_message(&mut self.socket, WriteMessage::AddIdentity(key))?;
84 self.expect_success()
85 }
86
87 pub fn remove_identity(&mut self, key: &PrivateKey) -> Result<()> {
89 write_message(&mut self.socket, WriteMessage::RemoveIdentity(key))?;
90 self.expect_success()
91 }
92
93 pub fn remove_all_identities(&mut self) -> Result<()> {
95 write_message(&mut self.socket, WriteMessage::RemoveAllIdentities)?;
96 self.expect_success()
97 }
98
99 pub fn sign(&mut self, key: &PublicKey, data: &[u8]) -> Result<Signature> {
103 write_message(&mut self.socket, WriteMessage::Sign(key, data))?;
104 match read_message(&mut self.socket)? {
105 ReadMessage::Signature(sig) => Ok(sig),
106 ReadMessage::Failure => Err(Error::RemoteFailure),
107 m => Err(unexpected_response(m)),
108 }
109 }
110
111 fn expect_success(&mut self) -> Result<()> {
112 let response = read_message(&mut self.socket)?;
113 match response {
114 ReadMessage::Success => Ok(()),
115 ReadMessage::Failure => Err(Error::RemoteFailure),
116 _ => Err(Error::InvalidMessage("Unexpected response".to_string())),
117 }
118 }
119}
120
121fn unexpected_response(message: ReadMessage) -> Error {
122 let error = format!("Agent responded with unexpected message '{:?}'", message);
123 Error::InvalidMessage(error)
124}