whatsapp_rust/
handshake.rs

1use crate::socket::{FrameSocket, NoiseSocket};
2use log::{debug, info};
3use std::sync::Arc;
4use thiserror::Error;
5use tokio::time::{Duration, timeout};
6use wacore::handshake::{HandshakeState, utils::HandshakeError as CoreHandshakeError};
7
8const NOISE_HANDSHAKE_RESPONSE_TIMEOUT: Duration = Duration::from_secs(20);
9
10#[derive(Debug, Error)]
11pub enum HandshakeError {
12    #[error("WebSocket error: {0}")]
13    Socket(#[from] crate::socket::error::SocketError),
14    #[error("Core handshake error: {0}")]
15    Core(#[from] CoreHandshakeError),
16    #[error("Timed out waiting for handshake response")]
17    Timeout,
18}
19
20type Result<T> = std::result::Result<T, HandshakeError>;
21
22pub async fn do_handshake(
23    device: &crate::store::Device,
24    frame_socket: &mut FrameSocket,
25    frames_rx: &mut tokio::sync::mpsc::Receiver<bytes::Bytes>,
26) -> Result<Arc<NoiseSocket>> {
27    let mut handshake_state = HandshakeState::new(&device.core)?;
28
29    debug!("--> Sending ClientHello");
30    let client_hello_bytes = handshake_state.build_client_hello()?;
31    frame_socket.send_frame(client_hello_bytes).await?;
32
33    let resp_frame = timeout(NOISE_HANDSHAKE_RESPONSE_TIMEOUT, frames_rx.recv())
34        .await
35        .map_err(|_| HandshakeError::Timeout)?
36        .ok_or(HandshakeError::Timeout)?;
37
38    debug!("<-- Received handshake response, building ClientFinish");
39    let client_finish_bytes =
40        handshake_state.read_server_hello_and_build_client_finish(&resp_frame)?;
41
42    debug!("--> Sending ClientFinish");
43    frame_socket.send_frame(client_finish_bytes).await?;
44
45    let (write_key, read_key) = handshake_state.finish()?;
46    info!(target: "Client", "Handshake complete, switching to encrypted communication");
47
48    let frame_socket_arc = std::sync::Arc::new(tokio::sync::Mutex::new(std::mem::replace(
49        frame_socket,
50        FrameSocket::new().0,
51    )));
52
53    Ok(Arc::new(NoiseSocket::new(
54        frame_socket_arc,
55        write_key,
56        read_key,
57    )))
58}