lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit e4517b061898a6d2651e0d584bbd633ccef6c43f
parent bf533e60cc795cc2779e061f5ec4e9c52a526019
Author: triesap <tyson@radroots.org>
Date:   Tue, 23 Jun 2026 06:51:09 +0000

simplex: join short invitations through link data

Diffstat:
Mcrates/simplex_agent_runtime/src/runtime.rs | 248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mcrates/simplex_agent_store/src/store.rs | 208++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
2 files changed, 340 insertions(+), 116 deletions(-)

diff --git a/crates/simplex_agent_runtime/src/runtime.rs b/crates/simplex_agent_runtime/src/runtime.rs @@ -346,9 +346,53 @@ impl RadrootsSimplexAgentRuntime { pub fn join_connection( &mut self, invitation: RadrootsSimplexAgentConnectionLink, - mut reply_queue: RadrootsSimplexSmpQueueUri, + reply_queue: RadrootsSimplexSmpQueueUri, now: u64, ) -> Result<String, RadrootsSimplexAgentRuntimeError> { + let connection = self.store.create_connection( + RadrootsSimplexAgentConnectionMode::Direct, + RadrootsSimplexAgentConnectionStatus::JoinPending, + None, + None, + ); + let connection_id = connection.id.clone(); + self.prepare_join_connection(&connection_id, invitation, reply_queue, now)?; + self.flush_store()?; + Ok(connection_id) + } + + pub fn join_short_invitation( + &mut self, + invitation: RadrootsSimplexAgentShortInvitationLink, + reply_queue: RadrootsSimplexSmpQueueUri, + now: u64, + ) -> Result<String, RadrootsSimplexAgentRuntimeError> { + let _ = short_invitation_server(&invitation)?; + let connection = self.store.create_connection( + RadrootsSimplexAgentConnectionMode::Direct, + RadrootsSimplexAgentConnectionStatus::JoinPending, + None, + None, + ); + self.store.enqueue_command( + &connection.id, + RadrootsSimplexAgentPendingCommandKind::SecureGetQueueLinkData { + invitation, + reply_queue, + }, + now, + )?; + self.flush_store()?; + Ok(connection.id) + } + + fn prepare_join_connection( + &mut self, + connection_id: &str, + invitation: RadrootsSimplexAgentConnectionLink, + mut reply_queue: RadrootsSimplexSmpQueueUri, + now: u64, + ) -> Result<(), RadrootsSimplexAgentRuntimeError> { let local_e2e_keypair = RadrootsSimplexSmpX25519Keypair::generate() .map_err(|error| RadrootsSimplexAgentRuntimeError::Runtime(error.to_string()))?; let invitation_e2e_public_key = @@ -436,12 +480,6 @@ impl RadrootsSimplexAgentRuntime { .map_err(|error| RadrootsSimplexAgentRuntimeError::Runtime(error.to_string()))?; None }; - let connection = self.store.create_connection( - RadrootsSimplexAgentConnectionMode::Direct, - RadrootsSimplexAgentConnectionStatus::JoinPending, - Some(invitation.clone()), - Some(ratchet_state), - ); let send_auth_state = self.store.generate_queue_auth_state()?; let send_descriptor = RadrootsSimplexAgentQueueDescriptor { queue_uri: invitation.invitation_queue.clone(), @@ -458,22 +496,29 @@ impl RadrootsSimplexAgentRuntime { primary: true, sender_key: None, }; + { + let connection = self.store.connection_mut(connection_id)?; + connection.mode = RadrootsSimplexAgentConnectionMode::Direct; + connection.status = RadrootsSimplexAgentConnectionStatus::JoinPending; + connection.invitation = Some(invitation); + connection.ratchet_state = Some(ratchet_state); + } self.store.add_queue( - &connection.id, + connection_id, send_descriptor.clone(), RadrootsSimplexAgentQueueRole::Send, true, send_auth_state, )?; self.store.add_queue( - &connection.id, + connection_id, receive_descriptor.clone(), RadrootsSimplexAgentQueueRole::Receive, true, receive_auth_state, )?; { - let connection = self.store.connection_mut(&connection.id)?; + let connection = self.store.connection_mut(connection_id)?; connection.local_e2e_public_key = Some(local_e2e_keypair.public_key.clone()); connection.local_e2e_private_key = Some(local_e2e_keypair.private_key); connection.local_x3dh_key_1 = Some(agent_x3dh_keypair(local_x3dh_key_1)); @@ -494,7 +539,7 @@ impl RadrootsSimplexAgentRuntime { queue.delivery_private_key = Some(delivery_keypair.private_key); } self.store.enqueue_command( - &connection.id, + connection_id, RadrootsSimplexAgentPendingCommandKind::SecureQueue { queue: send_descriptor.queue_address(), sender_key: send_descriptor.sender_key.clone(), @@ -502,14 +547,13 @@ impl RadrootsSimplexAgentRuntime { now, )?; self.store.enqueue_command( - &connection.id, + connection_id, RadrootsSimplexAgentPendingCommandKind::CreateQueue { descriptor: receive_descriptor.clone(), }, now, )?; - self.flush_store()?; - Ok(connection.id) + Ok(()) } pub fn allow_connection( @@ -1078,22 +1122,22 @@ impl RadrootsSimplexAgentRuntime { ) -> Result<RadrootsSimplexSmpTransportRequest, RadrootsSimplexAgentRuntimeError> { match &command.kind { RadrootsSimplexAgentPendingCommandKind::SecureGetQueueLinkData { - server, - link_id, - link_key, + invitation, .. } => { + let server = short_invitation_server(invitation)?; return Ok(self.server_transport_request( command.id, - server, - link_id.clone(), - RadrootsSimplexSmpCommand::LKey(link_key.clone()), + &server, + invitation.link_id.clone(), + RadrootsSimplexSmpCommand::LKey(invitation.link_key.clone()), )); } - RadrootsSimplexAgentPendingCommandKind::GetQueueLinkData { server, link_id } => { + RadrootsSimplexAgentPendingCommandKind::GetQueueLinkData { invitation, .. } => { + let server = short_invitation_server(invitation)?; return Ok(self.server_transport_request( command.id, - server, - link_id.clone(), + &server, + invitation.link_id.clone(), RadrootsSimplexSmpCommand::LGet, )); } @@ -1348,6 +1392,31 @@ impl RadrootsSimplexAgentRuntime { })) } + fn process_short_link_response( + &mut self, + command: &RadrootsSimplexAgentPendingCommand, + sender_id: Vec<u8>, + link_data: RadrootsSimplexSmpQueueLinkData, + ) -> Result<(), RadrootsSimplexAgentRuntimeError> { + let RadrootsSimplexAgentPendingCommandKind::GetQueueLinkData { + invitation, + reply_queue, + } = &command.kind + else { + return Err(RadrootsSimplexAgentRuntimeError::Runtime( + "SimpleX LNK response received for non-retrieval command".into(), + )); + }; + let mut connection_link = decrypt_short_invitation_link_data(invitation, &link_data)?; + connection_link.invitation_queue.sender_id = URL_SAFE_NO_PAD.encode(sender_id); + self.prepare_join_connection( + &command.connection_id, + connection_link, + reply_queue.clone(), + command.ready_at, + ) + } + fn apply_transport_response( &mut self, command: &RadrootsSimplexAgentPendingCommand, @@ -1388,6 +1457,16 @@ impl RadrootsSimplexAgentRuntime { RadrootsSimplexAgentCommandOutcome::Delivered, ) } + RadrootsSimplexSmpBrokerMessage::Lnk { + sender_id, + link_data, + } => { + self.process_short_link_response(command, sender_id, link_data)?; + self.record_command_outcome( + command.id, + RadrootsSimplexAgentCommandOutcome::Delivered, + ) + } _ => self .record_command_outcome(command.id, RadrootsSimplexAgentCommandOutcome::Delivered), } @@ -1455,6 +1534,19 @@ impl RadrootsSimplexAgentRuntime { .mark_queue_tested(&command.connection_id, queue)?; } } + RadrootsSimplexAgentPendingCommandKind::SecureGetQueueLinkData { + invitation, + reply_queue, + } => { + self.store.enqueue_command( + &command.connection_id, + RadrootsSimplexAgentPendingCommandKind::GetQueueLinkData { + invitation: invitation.clone(), + reply_queue: reply_queue.clone(), + }, + command.ready_at, + )?; + } _ => {} } Ok(()) @@ -2128,6 +2220,21 @@ fn prepare_short_invitation_link_data( }) } +fn short_invitation_server( + invitation: &RadrootsSimplexAgentShortInvitationLink, +) -> Result<RadrootsSimplexSmpServerAddress, RadrootsSimplexAgentRuntimeError> { + let server_identity = invitation.hosts.first().cloned().ok_or_else(|| { + RadrootsSimplexAgentRuntimeError::Runtime( + "SimpleX short invitation link does not include a relay host".into(), + ) + })?; + Ok(RadrootsSimplexSmpServerAddress { + server_identity, + hosts: invitation.hosts.clone(), + port: invitation.port, + }) +} + fn correlation_id_for_command(command_id: u64) -> RadrootsSimplexSmpCorrelationId { let digest = derive_material(b"simplex-command-correlation", &[&command_id.to_be_bytes()]); let mut correlation = [0_u8; RadrootsSimplexSmpCorrelationId::LENGTH]; @@ -2695,6 +2802,101 @@ mod tests { } #[test] + fn join_short_invitation_retrieves_link_data_and_continues_join() { + let mut runtime = RadrootsSimplexAgentRuntimeBuilder::new().build().unwrap(); + let created = runtime + .create_connection(invitation_queue(), b"e2e".to_vec(), false, 10) + .unwrap(); + let mut setup_transport = ScriptedTransport::with_responses(vec![ + ids_response(b"recipient", b"sender", b"server-dh"), + RadrootsSimplexSmpBrokerMessage::Ok, + ]); + runtime + .execute_ready_commands(&mut setup_transport, 30, 16) + .unwrap(); + let events = runtime.drain_events(16); + let Some(RadrootsSimplexAgentRuntimeEvent::InvitationReady { + invitation: short_invitation, + .. + }) = events.first() + else { + panic!("runtime should emit a short invitation event"); + }; + let short_link = runtime + .store + .connection(&created) + .unwrap() + .short_link + .as_ref() + .unwrap(); + let stored_link_data = RadrootsSimplexSmpQueueLinkData { + fixed_data: short_link.encrypted_fixed_data.clone().unwrap(), + user_data: short_link.encrypted_user_data.clone().unwrap(), + }; + let joined = runtime + .join_short_invitation(short_invitation.clone(), reply_queue(), 40) + .unwrap(); + let mut join_transport = ScriptedTransport::with_responses(vec![ + RadrootsSimplexSmpBrokerMessage::Ok, + RadrootsSimplexSmpBrokerMessage::Lnk { + sender_id: b"sender".to_vec(), + link_data: stored_link_data, + }, + RadrootsSimplexSmpBrokerMessage::Ok, + ids_response(b"recipient-2", b"sender-2", b"server-dh-2"), + RadrootsSimplexSmpBrokerMessage::Ok, + RadrootsSimplexSmpBrokerMessage::Ok, + ]); + runtime + .execute_ready_commands(&mut join_transport, 50, 16) + .unwrap(); + + assert_eq!(join_transport.requests.len(), 6); + let RadrootsSimplexSmpCommand::LKey(link_key) = &join_transport.requests[0].command else { + panic!("short invitation join should authorize link retrieval first"); + }; + assert_eq!(link_key, &short_invitation.link_key); + assert_eq!( + join_transport.requests[0].entity_id, + short_invitation.link_id.clone() + ); + assert!(matches!( + join_transport.requests[1].command, + RadrootsSimplexSmpCommand::LGet + )); + let RadrootsSimplexSmpCommand::SKey(_) = &join_transport.requests[2].command else { + panic!("short invitation join should secure the invitation send queue"); + }; + let RadrootsSimplexSmpCommand::New(_) = &join_transport.requests[3].command else { + panic!("short invitation join should create the reply queue"); + }; + let joined_connection = runtime.store.connection(&joined).unwrap(); + assert_eq!( + joined_connection.status, + RadrootsSimplexAgentConnectionStatus::JoinPending + ); + assert_eq!( + joined_connection.invitation.as_ref().unwrap().connection_id, + created.as_bytes().to_vec() + ); + assert_eq!( + runtime + .store + .primary_send_queue(&joined) + .unwrap() + .descriptor + .queue_uri + .sender_id, + URL_SAFE_NO_PAD.encode(b"sender") + ); + assert!(runtime.drain_events(16).iter().any(|event| matches!( + event, + RadrootsSimplexAgentRuntimeEvent::ConfirmationRequired { connection_id } + if connection_id == &joined + ))); + } + + #[test] fn join_confirmation_carries_sender_x3dh_params() { let mut runtime = RadrootsSimplexAgentRuntimeBuilder::new().build().unwrap(); let created = runtime diff --git a/crates/simplex_agent_store/src/store.rs b/crates/simplex_agent_store/src/store.rs @@ -30,10 +30,9 @@ use radroots_simplex_smp_crypto::prelude::RadrootsSimplexSmpEd25519Keypair; use radroots_simplex_smp_crypto::prelude::{ RADROOTS_SIMPLEX_OFFICIAL_AES_IV_LENGTH, RadrootsSimplexSmpSkippedMessageKey, }; -use radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpQueueLinkData; -#[cfg(feature = "std")] -use radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpQueueUri; -use radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpServerAddress; +use radroots_simplex_smp_proto::prelude::{ + RadrootsSimplexSmpQueueLinkData, RadrootsSimplexSmpQueueUri, RadrootsSimplexSmpServerAddress, +}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] @@ -206,13 +205,12 @@ pub enum RadrootsSimplexAgentPendingCommandKind { link_data: RadrootsSimplexSmpQueueLinkData, }, SecureGetQueueLinkData { - server: RadrootsSimplexSmpServerAddress, - link_id: Vec<u8>, - link_key: Vec<u8>, + invitation: RadrootsSimplexAgentShortInvitationLink, + reply_queue: RadrootsSimplexSmpQueueUri, }, GetQueueLinkData { - server: RadrootsSimplexSmpServerAddress, - link_id: Vec<u8>, + invitation: RadrootsSimplexAgentShortInvitationLink, + reply_queue: RadrootsSimplexSmpQueueUri, }, } @@ -330,14 +328,6 @@ struct RadrootsSimplexAgentQueueAddressSnapshot { } #[cfg(feature = "std")] -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -struct RadrootsSimplexAgentServerAddressSnapshot { - server_identity: String, - hosts: Vec<String>, - port: Option<u16>, -} - -#[cfg(feature = "std")] #[derive(Debug, Clone, Serialize, Deserialize)] struct RadrootsSimplexAgentShortLinkCredentialsSnapshot { scheme: String, @@ -354,6 +344,17 @@ struct RadrootsSimplexAgentShortLinkCredentialsSnapshot { #[cfg(feature = "std")] #[derive(Debug, Clone, Serialize, Deserialize)] +struct RadrootsSimplexAgentShortInvitationLinkSnapshot { + scheme: String, + hosts: Vec<String>, + port: Option<u16>, + server_key_hash: Option<Vec<u8>>, + link_id: Vec<u8>, + link_key: Vec<u8>, +} + +#[cfg(feature = "std")] +#[derive(Debug, Clone, Serialize, Deserialize)] struct RadrootsSimplexAgentQueueLinkDataSnapshot { fixed_data: Vec<u8>, user_data: Vec<u8>, @@ -446,13 +447,12 @@ enum RadrootsSimplexAgentPendingCommandKindSnapshot { link_data: RadrootsSimplexAgentQueueLinkDataSnapshot, }, SecureGetQueueLinkData { - server: RadrootsSimplexAgentServerAddressSnapshot, - link_id: Vec<u8>, - link_key: Vec<u8>, + invitation: RadrootsSimplexAgentShortInvitationLinkSnapshot, + reply_queue: String, }, GetQueueLinkData { - server: RadrootsSimplexAgentServerAddressSnapshot, - link_id: Vec<u8>, + invitation: RadrootsSimplexAgentShortInvitationLinkSnapshot, + reply_queue: String, }, } @@ -2209,14 +2209,8 @@ fn queue_descriptor_to_snapshot( fn queue_descriptor_from_snapshot( snapshot: RadrootsSimplexAgentQueueDescriptorSnapshot, ) -> Result<RadrootsSimplexAgentQueueDescriptor, RadrootsSimplexAgentStoreError> { - let queue_uri = RadrootsSimplexSmpQueueUri::parse(&snapshot.queue_uri).map_err(|error| { - RadrootsSimplexAgentStoreError::Persistence(format!( - "failed to parse SimpleX queue uri `{}`: {error}", - snapshot.queue_uri - )) - })?; Ok(RadrootsSimplexAgentQueueDescriptor { - queue_uri, + queue_uri: queue_uri_from_string(&snapshot.queue_uri)?, replaced_queue: snapshot .replaced_queue .map(queue_address_from_snapshot) @@ -2227,6 +2221,17 @@ fn queue_descriptor_from_snapshot( } #[cfg(feature = "std")] +fn queue_uri_from_string( + value: &str, +) -> Result<RadrootsSimplexSmpQueueUri, RadrootsSimplexAgentStoreError> { + RadrootsSimplexSmpQueueUri::parse(value).map_err(|error| { + RadrootsSimplexAgentStoreError::Persistence(format!( + "failed to parse SimpleX queue uri `{value}`: {error}" + )) + }) +} + +#[cfg(feature = "std")] fn queue_address_to_snapshot( address: RadrootsSimplexAgentQueueAddress, ) -> RadrootsSimplexAgentQueueAddressSnapshot { @@ -2258,33 +2263,6 @@ fn queue_address_from_snapshot( } #[cfg(feature = "std")] -fn server_address_to_snapshot( - server: RadrootsSimplexSmpServerAddress, -) -> RadrootsSimplexAgentServerAddressSnapshot { - RadrootsSimplexAgentServerAddressSnapshot { - server_identity: server.server_identity, - hosts: server.hosts, - port: server.port, - } -} - -#[cfg(feature = "std")] -fn server_address_from_snapshot( - snapshot: RadrootsSimplexAgentServerAddressSnapshot, -) -> Result<RadrootsSimplexSmpServerAddress, RadrootsSimplexAgentStoreError> { - if snapshot.server_identity.is_empty() || snapshot.hosts.is_empty() { - return Err(RadrootsSimplexAgentStoreError::Persistence( - "invalid SimpleX server address snapshot".into(), - )); - } - Ok(RadrootsSimplexSmpServerAddress { - server_identity: snapshot.server_identity, - hosts: snapshot.hosts, - port: snapshot.port, - }) -} - -#[cfg(feature = "std")] fn short_link_to_snapshot( credentials: RadrootsSimplexAgentShortLinkCredentials, ) -> RadrootsSimplexAgentShortLinkCredentialsSnapshot { @@ -2321,6 +2299,34 @@ fn short_link_from_snapshot( } #[cfg(feature = "std")] +fn short_invitation_to_snapshot( + invitation: RadrootsSimplexAgentShortInvitationLink, +) -> RadrootsSimplexAgentShortInvitationLinkSnapshot { + RadrootsSimplexAgentShortInvitationLinkSnapshot { + scheme: encode_short_link_scheme(invitation.scheme).into(), + hosts: invitation.hosts, + port: invitation.port, + server_key_hash: invitation.server_key_hash, + link_id: invitation.link_id, + link_key: invitation.link_key, + } +} + +#[cfg(feature = "std")] +fn short_invitation_from_snapshot( + snapshot: RadrootsSimplexAgentShortInvitationLinkSnapshot, +) -> Result<RadrootsSimplexAgentShortInvitationLink, RadrootsSimplexAgentStoreError> { + Ok(RadrootsSimplexAgentShortInvitationLink { + scheme: decode_short_link_scheme(&snapshot.scheme)?, + hosts: snapshot.hosts, + port: snapshot.port, + server_key_hash: snapshot.server_key_hash, + link_id: snapshot.link_id, + link_key: snapshot.link_key, + }) +} + +#[cfg(feature = "std")] fn queue_link_data_to_snapshot( link_data: RadrootsSimplexSmpQueueLinkData, ) -> RadrootsSimplexAgentQueueLinkDataSnapshot { @@ -2569,20 +2575,19 @@ fn command_kind_to_snapshot( link_data: queue_link_data_to_snapshot(link_data), }, RadrootsSimplexAgentPendingCommandKind::SecureGetQueueLinkData { - server, - link_id, - link_key, + invitation, + reply_queue, } => RadrootsSimplexAgentPendingCommandKindSnapshot::SecureGetQueueLinkData { - server: server_address_to_snapshot(server), - link_id, - link_key, + invitation: short_invitation_to_snapshot(invitation), + reply_queue: reply_queue.to_string(), + }, + RadrootsSimplexAgentPendingCommandKind::GetQueueLinkData { + invitation, + reply_queue, + } => RadrootsSimplexAgentPendingCommandKindSnapshot::GetQueueLinkData { + invitation: short_invitation_to_snapshot(invitation), + reply_queue: reply_queue.to_string(), }, - RadrootsSimplexAgentPendingCommandKind::GetQueueLinkData { server, link_id } => { - RadrootsSimplexAgentPendingCommandKindSnapshot::GetQueueLinkData { - server: server_address_to_snapshot(server), - link_id, - } - } }) } @@ -2664,20 +2669,19 @@ fn command_kind_from_snapshot( link_data: queue_link_data_from_snapshot(link_data), }, RadrootsSimplexAgentPendingCommandKindSnapshot::SecureGetQueueLinkData { - server, - link_id, - link_key, + invitation, + reply_queue, } => RadrootsSimplexAgentPendingCommandKind::SecureGetQueueLinkData { - server: server_address_from_snapshot(server)?, - link_id, - link_key, + invitation: short_invitation_from_snapshot(invitation)?, + reply_queue: queue_uri_from_string(&reply_queue)?, + }, + RadrootsSimplexAgentPendingCommandKindSnapshot::GetQueueLinkData { + invitation, + reply_queue, + } => RadrootsSimplexAgentPendingCommandKind::GetQueueLinkData { + invitation: short_invitation_from_snapshot(invitation)?, + reply_queue: queue_uri_from_string(&reply_queue)?, }, - RadrootsSimplexAgentPendingCommandKindSnapshot::GetQueueLinkData { server, link_id } => { - RadrootsSimplexAgentPendingCommandKind::GetQueueLinkData { - server: server_address_from_snapshot(server)?, - link_id, - } - } }) } @@ -2824,6 +2828,17 @@ mod tests { } } + fn sample_short_invitation_link(link_id: Vec<u8>) -> RadrootsSimplexAgentShortInvitationLink { + RadrootsSimplexAgentShortInvitationLink { + scheme: RadrootsSimplexAgentShortLinkScheme::Simplex, + hosts: vec!["relay-a.example".to_owned(), "relay-b.example".to_owned()], + port: Some(5223), + server_key_hash: Some(vec![5_u8; 32]), + link_id, + link_key: b"short-link-key-must-be-secret!!".to_vec(), + } + } + #[cfg(feature = "std")] fn persisted_store_with_secret_material(path: &Path) -> String { let mut store = RadrootsSimplexAgentStore::open(path).unwrap(); @@ -2972,6 +2987,13 @@ mod tests { .prepare_outbound_message(&connection.id, b"persisted".to_vec()) .unwrap(); let queue = sample_descriptor(true).queue_address(); + let short_reply_queue = sample_descriptor_with_uri( + "smp://aGVsbG8@relay.example/cmVwbHk#/?v=4&dh=cmVwbHkta2V5&q=m", + true, + ) + .queue_uri; + let secure_short_invitation = sample_short_invitation_link(vec![2_u8; 24]); + let get_short_invitation = sample_short_invitation_link(vec![3_u8; 24]); store .enqueue_command( &connection.id, @@ -3016,9 +3038,8 @@ mod tests { .enqueue_command( &connection.id, RadrootsSimplexAgentPendingCommandKind::SecureGetQueueLinkData { - server: queue.server.clone(), - link_id: vec![2_u8; 24], - link_key: b"retrieval-short-link-key-secret".to_vec(), + invitation: secure_short_invitation.clone(), + reply_queue: short_reply_queue.clone(), }, 13, ) @@ -3027,8 +3048,8 @@ mod tests { .enqueue_command( &connection.id, RadrootsSimplexAgentPendingCommandKind::GetQueueLinkData { - server: queue.server.clone(), - link_id: vec![3_u8; 24], + invitation: get_short_invitation.clone(), + reply_queue: short_reply_queue.clone(), }, 14, ) @@ -3297,17 +3318,18 @@ mod tests { assert!(loaded.pending_commands.values().any(|command| matches!( &command.kind, RadrootsSimplexAgentPendingCommandKind::SecureGetQueueLinkData { - server, - link_id, - link_key - } if server == &queue.server - && link_id.as_slice() == &[2_u8; 24] - && link_key.as_slice() == b"retrieval-short-link-key-secret" + invitation, + reply_queue + } if invitation == &secure_short_invitation + && reply_queue == &short_reply_queue ))); assert!(loaded.pending_commands.values().any(|command| matches!( &command.kind, - RadrootsSimplexAgentPendingCommandKind::GetQueueLinkData { server, link_id } - if server == &queue.server && link_id.as_slice() == &[3_u8; 24] + RadrootsSimplexAgentPendingCommandKind::GetQueueLinkData { + invitation, + reply_queue + } if invitation == &get_short_invitation + && reply_queue == &short_reply_queue ))); assert!( loaded