//! Shared helpers for the integration tests: v2 client sessions against a //! live server, and raw frame construction. use omnivox::{Cereal, CodecError, Session, encrypt_with_nonce, frame_nonce, handshake::perform}; use tokio::net::TcpStream; use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf}; #[derive(Debug, Default)] pub struct Msg(pub Vec); impl Cereal for Msg { fn encode(&self, out: &mut Vec) { omnivox::write_byte_vec(out, &self.0); } fn decode(bytes: &[u8]) -> Result { Ok(Self(omnivox::Reader::new(bytes).byte_vec()?)) } } pub const TEST_PSK: [u8; 32] = [42u8; 32]; /// Builds one framed message with the given sequence number. pub fn frame(key: &[u8; 32], counter: u64, msg: &[u8]) -> Vec { let mut plain = Vec::new(); Msg(msg.to_vec()).encode(&mut plain); let pkt = encrypt_with_nonce(key, &frame_nonce(counter), &plain); let mut bytes = Vec::new(); pkt.encode(&mut bytes); let mut out = Vec::new(); out.extend_from_slice(&(bytes.len() as u32).to_le_bytes()); out.extend_from_slice(&bytes); out } /// Connects and completes the v2 handshake as the client role, returning /// the raw halves plus the session keys for manual framing. pub async fn client_session(port: u16, psk: &[u8; 32]) -> (OwnedReadHalf, OwnedWriteHalf, Session) { let stream = TcpStream::connect(("127.0.0.1", port)).await.unwrap(); let (mut r, mut w) = stream.into_split(); let session = perform(&mut r, &mut w, psk, false).await.unwrap(); (r, w, session) }