sentinelpass_protocol/
connection.rs1use crate::session::{self, SessionCrypto, SESSION_READ_DEADLINE};
7use crate::transport::{TransportError, TransportResult};
8
9pub enum TransportConnection {
11 #[cfg(unix)]
12 Unix(crate::transport::unix::UnixSocketConnection),
13 #[cfg(windows)]
14 Windows(crate::transport::windows::WindowsNamedPipeConnection),
15}
16
17#[cfg(unix)]
18impl From<crate::transport::unix::UnixSocketConnection> for TransportConnection {
19 fn from(conn: crate::transport::unix::UnixSocketConnection) -> Self {
20 Self::Unix(conn)
21 }
22}
23
24#[cfg(windows)]
25impl From<crate::transport::windows::WindowsNamedPipeConnection> for TransportConnection {
26 fn from(conn: crate::transport::windows::WindowsNamedPipeConnection) -> Self {
27 Self::Windows(conn)
28 }
29}
30
31impl TransportConnection {
32 async fn read_frame(&mut self) -> TransportResult<Vec<u8>> {
33 match self {
34 #[cfg(unix)]
35 TransportConnection::Unix(conn) => conn.read_message().await,
36 #[cfg(windows)]
37 TransportConnection::Windows(conn) => conn.read_message().await,
38 }
39 }
40
41 async fn write_frame(&mut self, data: &[u8]) -> TransportResult<()> {
42 match self {
43 #[cfg(unix)]
44 TransportConnection::Unix(conn) => conn.write_message(data).await,
45 #[cfg(windows)]
46 TransportConnection::Windows(conn) => conn.write_message(data).await,
47 }
48 }
49}
50
51pub enum IpcConnection {
53 Secured {
55 conn: Box<TransportConnection>,
56 crypto: SessionCrypto,
57 },
58 Plain { conn: Box<TransportConnection> },
61}
62
63impl IpcConnection {
64 pub async fn connect_client(
67 mut conn: TransportConnection,
68 token: &str,
69 ) -> TransportResult<Self> {
70 let (hello, client_random) = session::new_hello();
71 let hello_bytes = serde_json::to_vec(&hello)
72 .map_err(|e| TransportError::Other(format!("hello encode: {e}")))?;
73 tokio::time::timeout(SESSION_READ_DEADLINE, conn.write_frame(&hello_bytes))
74 .await
75 .map_err(|_| TransportError::Timeout)??;
76
77 let reply = tokio::time::timeout(SESSION_READ_DEADLINE, conn.read_frame())
78 .await
79 .map_err(|_| TransportError::Timeout)??;
80 let accept = session::parse_accept(&reply)?;
81 let server_random = session::server_random_of(&accept)?;
82 let (c2s, s2c) = session::derive_directional_keys(token, &client_random, &server_random)?;
83 Ok(IpcConnection::Secured {
84 conn: Box::new(conn),
85 crypto: SessionCrypto::client(c2s, s2c),
86 })
87 }
88
89 pub async fn accept_server(
94 mut conn: TransportConnection,
95 token: &str,
96 ) -> TransportResult<(Self, Option<Vec<u8>>)> {
97 let first = tokio::time::timeout(SESSION_READ_DEADLINE, conn.read_frame())
98 .await
99 .map_err(|_| TransportError::Timeout)??;
100
101 if session::is_session_hello(&first) {
102 let hello = session::parse_hello(&first)?;
103 let client_random = session::client_random_of(&hello)?;
104 let (accept, server_random) = session::new_accept();
105 let accept_bytes = serde_json::to_vec(&accept)
106 .map_err(|e| TransportError::Other(format!("accept encode: {e}")))?;
107 tokio::time::timeout(SESSION_READ_DEADLINE, conn.write_frame(&accept_bytes))
108 .await
109 .map_err(|_| TransportError::Timeout)??;
110 let (c2s, s2c) =
111 session::derive_directional_keys(token, &client_random, &server_random)?;
112 Ok((
113 IpcConnection::Secured {
114 conn: Box::new(conn),
115 crypto: SessionCrypto::server(c2s, s2c),
116 },
117 None,
118 ))
119 } else {
120 tracing::warn!(
123 "accepted LEGACY plaintext IPC connection (no session handshake) — \
124 upgrade the client; the plaintext window is removed in 1.0"
125 );
126 Ok((
127 IpcConnection::Plain {
128 conn: Box::new(conn),
129 },
130 Some(first),
131 ))
132 }
133 }
134
135 pub async fn send_frame(&mut self, envelope_bytes: &[u8]) -> TransportResult<()> {
138 match self {
139 IpcConnection::Secured { conn, crypto } => {
140 let sealed = crypto.seal(envelope_bytes)?;
141 tokio::time::timeout(SESSION_READ_DEADLINE, conn.write_frame(&sealed))
142 .await
143 .map_err(|_| TransportError::Timeout)??;
144 Ok(())
145 }
146 IpcConnection::Plain { conn } => {
147 tokio::time::timeout(SESSION_READ_DEADLINE, conn.write_frame(envelope_bytes))
148 .await
149 .map_err(|_| TransportError::Timeout)??;
150 Ok(())
151 }
152 }
153 }
154
155 pub async fn recv_frame(&mut self) -> TransportResult<Vec<u8>> {
158 let raw = tokio::time::timeout(SESSION_READ_DEADLINE, self.read_raw())
159 .await
160 .map_err(|_| TransportError::Timeout)??;
161 match self {
162 IpcConnection::Secured { crypto, .. } => crypto.open(&raw),
163 IpcConnection::Plain { .. } => Ok(raw),
164 }
165 }
166
167 async fn read_raw(&mut self) -> TransportResult<Vec<u8>> {
168 match self {
169 IpcConnection::Secured { conn, .. } => conn.read_frame().await,
170 IpcConnection::Plain { conn } => conn.read_frame().await,
171 }
172 }
173}