enigma-protocol 0.1.0

High-level orchestrator that composes the Enigma crates into a production-ready messaging protocol
Documentation
use crate::client::MessengerClient;
use crate::error::{EnigmaProtocolError, Result};
use crate::session::Session;
use crate::transport::in_memory_duplex_pair;
use crate::types::{InitiatorOrResponder, SessionBootstrap};
use enigma_identity::LocalIdentity;
use enigma_packet::{Message, MessageMeta, MessageType};
use uuid::Uuid;

#[test]
fn session_bootstrap_produces_matching_conversation_id() -> Result<()> {
    let secret = [11u8; 32];
    let initiator = Session::new(
        "alice",
        "bob",
        &SessionBootstrap::PreSharedSecret {
            secret32: secret,
            role: InitiatorOrResponder::Initiator,
            remote_dh_pub: None,
        },
    )?;
    let responder = Session::new(
        "bob",
        "alice",
        &SessionBootstrap::PreSharedSecret {
            secret32: secret,
            role: InitiatorOrResponder::Responder,
            remote_dh_pub: None,
        },
    )?;
    assert_eq!(initiator.conversation_id(), responder.conversation_id());
    Ok(())
}

#[tokio::test]
async fn error_for_unknown_session() {
    let alice_identity = LocalIdentity::new("alice").expect("identity");
    let (transport, _other) = in_memory_duplex_pair(8);
    let mut client = MessengerClient::new(alice_identity, transport);
    let err = client.send_text("missing", "hello").await.unwrap_err();
    assert!(matches!(err, EnigmaProtocolError::UnknownSession));
}

#[test]
fn associated_data_mismatch_rejected() -> Result<()> {
    let secret = [3u8; 32];
    let mut sender = Session::new(
        "alice",
        "bob",
        &SessionBootstrap::PreSharedSecret {
            secret32: secret,
            role: InitiatorOrResponder::Initiator,
            remote_dh_pub: None,
        },
    )?;
    let mut receiver = Session::new(
        "bob",
        "alice",
        &SessionBootstrap::PreSharedSecret {
            secret32: secret,
            role: InitiatorOrResponder::Responder,
            remote_dh_pub: None,
        },
    )?;
    let message = sample_message("alice", "bob", b"payload");
    let packet = sender.encrypt_message(&message)?;
    let decoded = receiver.decrypt_packet(&packet)?;
    assert_eq!(decoded.payload, b"payload");
    let mut wrong_receiver = Session::new(
        "charlie",
        "alice",
        &SessionBootstrap::PreSharedSecret {
            secret32: secret,
            role: InitiatorOrResponder::Responder,
            remote_dh_pub: None,
        },
    )?;
    assert!(wrong_receiver.decrypt_packet(&packet).is_err());
    Ok(())
}

fn sample_message(sender: &str, receiver: &str, payload: &[u8]) -> Message {
    Message {
        id: Uuid::new_v4(),
        sender: sender.to_string(),
        receiver: receiver.to_string(),
        timestamp_ms: 1,
        msg_type: MessageType::Text,
        payload: payload.to_vec(),
        meta: MessageMeta::Basic {
            content_type: Some("text/plain".to_string()),
        },
    }
}