wire.rs (100341B)
1 use crate::error::RadrootsSimplexSmpProtoError; 2 use crate::uri::RadrootsSimplexSmpQueueMode; 3 use crate::version::{ 4 RADROOTS_SIMPLEX_SMP_BLOCKED_ENTITY_TRANSPORT_VERSION, 5 RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION, RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION, 6 RADROOTS_SIMPLEX_SMP_NEW_NOTIFIER_CREDENTIALS_TRANSPORT_VERSION, 7 RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION, 8 RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION, 9 RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION, RadrootsSimplexSmpVersionRange, 10 }; 11 use alloc::boxed::Box; 12 use alloc::string::{String, ToString}; 13 use alloc::vec::Vec; 14 use core::net::Ipv6Addr; 15 use core::str::FromStr; 16 17 const TAG_NEW: &[u8] = b"NEW"; 18 const TAG_SUB: &[u8] = b"SUB"; 19 const TAG_SUBS: &[u8] = b"SUBS"; 20 const TAG_KEY: &[u8] = b"KEY"; 21 const TAG_RKEY: &[u8] = b"RKEY"; 22 const TAG_LSET: &[u8] = b"LSET"; 23 const TAG_LDEL: &[u8] = b"LDEL"; 24 const TAG_NKEY: &[u8] = b"NKEY"; 25 const TAG_NDEL: &[u8] = b"NDEL"; 26 const TAG_GET: &[u8] = b"GET"; 27 const TAG_ACK: &[u8] = b"ACK"; 28 const TAG_OFF: &[u8] = b"OFF"; 29 const TAG_DEL: &[u8] = b"DEL"; 30 const TAG_QUE: &[u8] = b"QUE"; 31 const TAG_SKEY: &[u8] = b"SKEY"; 32 const TAG_SEND: &[u8] = b"SEND"; 33 const TAG_PING: &[u8] = b"PING"; 34 const TAG_LKEY: &[u8] = b"LKEY"; 35 const TAG_LGET: &[u8] = b"LGET"; 36 const TAG_NSUB: &[u8] = b"NSUB"; 37 const TAG_NSUBS: &[u8] = b"NSUBS"; 38 const TAG_PRXY: &[u8] = b"PRXY"; 39 const TAG_PFWD: &[u8] = b"PFWD"; 40 const TAG_RFWD: &[u8] = b"RFWD"; 41 42 const TAG_IDS: &[u8] = b"IDS"; 43 const TAG_LNK: &[u8] = b"LNK"; 44 const TAG_SOK: &[u8] = b"SOK"; 45 const TAG_SOKS: &[u8] = b"SOKS"; 46 const TAG_NID: &[u8] = b"NID"; 47 const TAG_MSG: &[u8] = b"MSG"; 48 const TAG_NMSG: &[u8] = b"NMSG"; 49 const TAG_PKEY: &[u8] = b"PKEY"; 50 const TAG_RRES: &[u8] = b"RRES"; 51 const TAG_PRES: &[u8] = b"PRES"; 52 const TAG_END: &[u8] = b"END"; 53 const TAG_ENDS: &[u8] = b"ENDS"; 54 const TAG_DELD: &[u8] = b"DELD"; 55 const TAG_INFO: &[u8] = b"INFO"; 56 const TAG_OK: &[u8] = b"OK"; 57 const TAG_ERR: &[u8] = b"ERR"; 58 const TAG_PONG: &[u8] = b"PONG"; 59 60 const COMMAND_ERR_UNKNOWN: &[u8] = b"UNKNOWN"; 61 const COMMAND_ERR_SYNTAX: &[u8] = b"SYNTAX"; 62 const COMMAND_ERR_PROHIBITED: &[u8] = b"PROHIBITED"; 63 const COMMAND_ERR_NO_AUTH: &[u8] = b"NO_AUTH"; 64 const COMMAND_ERR_HAS_AUTH: &[u8] = b"HAS_AUTH"; 65 const COMMAND_ERR_NO_ENTITY: &[u8] = b"NO_ENTITY"; 66 const COMMAND_ERR_NO_QUEUE: &[u8] = b"NO_QUEUE"; 67 68 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 69 pub enum RadrootsSimplexSmpSubscriptionMode { 70 Subscribe, 71 OnlyCreate, 72 } 73 74 #[derive(Debug, Clone, PartialEq, Eq)] 75 pub struct RadrootsSimplexSmpQueueLinkData { 76 pub fixed_data: Vec<u8>, 77 pub user_data: Vec<u8>, 78 } 79 80 #[derive(Debug, Clone, PartialEq, Eq)] 81 pub struct RadrootsSimplexSmpMessagingQueueRequest { 82 pub sender_id: Vec<u8>, 83 pub link_data: RadrootsSimplexSmpQueueLinkData, 84 } 85 86 #[derive(Debug, Clone, PartialEq, Eq)] 87 pub struct RadrootsSimplexSmpContactQueueRequest { 88 pub link_id: Vec<u8>, 89 pub sender_id: Vec<u8>, 90 pub link_data: RadrootsSimplexSmpQueueLinkData, 91 } 92 93 #[derive(Debug, Clone, PartialEq, Eq)] 94 pub struct RadrootsSimplexSmpKeyList { 95 pub first: Vec<u8>, 96 pub rest: Vec<Vec<u8>>, 97 } 98 99 #[derive(Debug, Clone, PartialEq, Eq)] 100 pub struct RadrootsSimplexSmpProtocolServer { 101 pub hosts: Vec<String>, 102 pub port: String, 103 pub key_hash: Vec<u8>, 104 } 105 106 #[derive(Debug, Clone, PartialEq, Eq)] 107 pub struct RadrootsSimplexSmpCertChainPublicKey { 108 pub certificate_chain: Vec<Vec<u8>>, 109 pub signed_public_key: Vec<u8>, 110 } 111 112 #[derive(Debug, Clone, PartialEq, Eq)] 113 pub enum RadrootsSimplexSmpBlockingReason { 114 Spam, 115 Content, 116 Other(String), 117 } 118 119 #[derive(Debug, Clone, PartialEq, Eq)] 120 pub struct RadrootsSimplexSmpBlockingInfo { 121 pub reason: RadrootsSimplexSmpBlockingReason, 122 } 123 124 #[derive(Debug, Clone, PartialEq, Eq)] 125 pub enum RadrootsSimplexSmpHandshakeError { 126 Parse, 127 Identity, 128 BadAuth, 129 BadService, 130 Other(String), 131 } 132 133 #[derive(Debug, Clone, PartialEq, Eq)] 134 pub enum RadrootsSimplexSmpTransportError { 135 Block, 136 Version, 137 LargeMsg, 138 Session, 139 NoAuth, 140 Handshake(RadrootsSimplexSmpHandshakeError), 141 } 142 143 #[derive(Debug, Clone, PartialEq, Eq)] 144 pub enum RadrootsSimplexSmpNetworkError { 145 Connect(String), 146 Tls(String), 147 UnknownCa, 148 Failed, 149 Timeout, 150 Subscribe(String), 151 } 152 153 #[derive(Debug, Clone, PartialEq, Eq)] 154 pub enum RadrootsSimplexSmpBrokerError { 155 Response(String), 156 Unexpected(String), 157 Network(RadrootsSimplexSmpNetworkError), 158 Host, 159 NoService, 160 Transport(RadrootsSimplexSmpTransportError), 161 Timeout, 162 } 163 164 #[derive(Debug, Clone, PartialEq, Eq)] 165 pub enum RadrootsSimplexSmpProxyError { 166 Protocol(Box<RadrootsSimplexSmpError>), 167 Broker(RadrootsSimplexSmpBrokerError), 168 BasicAuth, 169 NoSession, 170 } 171 172 #[derive(Debug, Clone, PartialEq, Eq)] 173 pub enum RadrootsSimplexSmpQueueRequestData { 174 Messaging(Option<RadrootsSimplexSmpMessagingQueueRequest>), 175 Contact(Option<RadrootsSimplexSmpContactQueueRequest>), 176 } 177 178 impl RadrootsSimplexSmpQueueRequestData { 179 pub const fn queue_mode(&self) -> RadrootsSimplexSmpQueueMode { 180 match self { 181 Self::Messaging(_) => RadrootsSimplexSmpQueueMode::Messaging, 182 Self::Contact(_) => RadrootsSimplexSmpQueueMode::Contact, 183 } 184 } 185 } 186 187 #[derive(Debug, Clone, PartialEq, Eq)] 188 pub struct RadrootsSimplexSmpNewNotifierCredentials { 189 pub notifier_auth_public_key: Vec<u8>, 190 pub recipient_notification_dh_public_key: Vec<u8>, 191 } 192 193 #[derive(Debug, Clone, PartialEq, Eq)] 194 pub struct RadrootsSimplexSmpServerNotifierCredentials { 195 pub notifier_id: Vec<u8>, 196 pub server_notification_dh_public_key: Vec<u8>, 197 } 198 199 #[derive(Debug, Clone, PartialEq, Eq)] 200 pub struct RadrootsSimplexSmpNewQueueRequest { 201 pub recipient_auth_public_key: Vec<u8>, 202 pub recipient_dh_public_key: Vec<u8>, 203 pub basic_auth: Option<String>, 204 pub subscription_mode: RadrootsSimplexSmpSubscriptionMode, 205 pub queue_request_data: Option<RadrootsSimplexSmpQueueRequestData>, 206 pub notifier_credentials: Option<RadrootsSimplexSmpNewNotifierCredentials>, 207 } 208 209 impl RadrootsSimplexSmpNewQueueRequest { 210 pub const fn sender_can_secure(&self) -> bool { 211 matches!( 212 self.queue_request_data, 213 Some(RadrootsSimplexSmpQueueRequestData::Messaging(_)) 214 ) 215 } 216 } 217 218 #[derive(Debug, Clone, PartialEq, Eq)] 219 pub struct RadrootsSimplexSmpMessageFlags { 220 pub notification: bool, 221 pub reserved: Vec<u8>, 222 } 223 224 impl RadrootsSimplexSmpMessageFlags { 225 pub const fn notifications_enabled() -> Self { 226 Self { 227 notification: true, 228 reserved: Vec::new(), 229 } 230 } 231 232 pub const fn notifications_disabled() -> Self { 233 Self { 234 notification: false, 235 reserved: Vec::new(), 236 } 237 } 238 } 239 240 impl Default for RadrootsSimplexSmpMessageFlags { 241 fn default() -> Self { 242 Self::notifications_disabled() 243 } 244 } 245 246 #[derive(Debug, Clone, PartialEq, Eq)] 247 pub struct RadrootsSimplexSmpSendCommand { 248 pub flags: RadrootsSimplexSmpMessageFlags, 249 pub message_body: Vec<u8>, 250 } 251 252 #[derive(Debug, Clone, PartialEq, Eq)] 253 pub enum RadrootsSimplexSmpCommand { 254 New(RadrootsSimplexSmpNewQueueRequest), 255 Sub, 256 Subs, 257 Key(Vec<u8>), 258 RKey(RadrootsSimplexSmpKeyList), 259 LSet { 260 link_id: Vec<u8>, 261 link_data: RadrootsSimplexSmpQueueLinkData, 262 }, 263 LDel, 264 NKey { 265 notifier_auth_public_key: Vec<u8>, 266 recipient_notification_dh_public_key: Vec<u8>, 267 }, 268 NDel, 269 Get, 270 Ack(Vec<u8>), 271 Off, 272 Del, 273 Que, 274 SKey(Vec<u8>), 275 Send(RadrootsSimplexSmpSendCommand), 276 Ping, 277 LKey(Vec<u8>), 278 LGet, 279 NSub, 280 NSubs, 281 Prxy { 282 server: RadrootsSimplexSmpProtocolServer, 283 basic_auth: Option<String>, 284 }, 285 PFwd { 286 relay_version: u16, 287 public_key: Vec<u8>, 288 encrypted_transmission: Vec<u8>, 289 }, 290 RFwd(Vec<u8>), 291 } 292 293 #[derive(Debug, Clone, PartialEq, Eq)] 294 pub struct RadrootsSimplexSmpQueueIdsResponse { 295 pub recipient_id: Vec<u8>, 296 pub sender_id: Vec<u8>, 297 pub server_dh_public_key: Vec<u8>, 298 pub queue_mode: Option<RadrootsSimplexSmpQueueMode>, 299 pub link_id: Option<Vec<u8>>, 300 pub service_id: Option<Vec<u8>>, 301 pub server_notification_credentials: Option<RadrootsSimplexSmpServerNotifierCredentials>, 302 } 303 304 impl RadrootsSimplexSmpQueueIdsResponse { 305 pub const fn sender_can_secure(&self) -> bool { 306 matches!( 307 self.queue_mode, 308 Some(RadrootsSimplexSmpQueueMode::Messaging) 309 ) 310 } 311 } 312 313 #[derive(Debug, Clone, PartialEq, Eq)] 314 pub struct RadrootsSimplexSmpNotifierIdsResponse { 315 pub notifier_id: Vec<u8>, 316 pub server_notification_dh_public_key: Vec<u8>, 317 } 318 319 #[derive(Debug, Clone, PartialEq, Eq)] 320 pub struct RadrootsSimplexSmpReceivedMessage { 321 pub message_id: Vec<u8>, 322 pub encrypted_body: Vec<u8>, 323 } 324 325 #[derive(Debug, Clone, PartialEq, Eq)] 326 pub enum RadrootsSimplexSmpCommandError { 327 Unknown, 328 Syntax, 329 Prohibited, 330 NoAuth, 331 HasAuth, 332 NoEntity, 333 Other(Vec<u8>), 334 } 335 336 #[derive(Debug, Clone, PartialEq, Eq)] 337 pub enum RadrootsSimplexSmpError { 338 Block, 339 Session, 340 Command(RadrootsSimplexSmpCommandError), 341 Proxy(RadrootsSimplexSmpProxyError), 342 Auth, 343 Blocked(RadrootsSimplexSmpBlockingInfo), 344 Service, 345 Crypto, 346 Quota, 347 Store(String), 348 NoMsg, 349 LargeMsg, 350 Expired, 351 Internal, 352 Duplicate, 353 Other(Vec<u8>), 354 } 355 356 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 357 pub struct RadrootsSimplexSmpCorrelationId([u8; 24]); 358 359 impl RadrootsSimplexSmpCorrelationId { 360 pub const LENGTH: usize = 24; 361 362 pub const fn new(bytes: [u8; 24]) -> Self { 363 Self(bytes) 364 } 365 366 pub fn from_slice(value: &[u8]) -> Result<Self, RadrootsSimplexSmpProtoError> { 367 if value.len() != Self::LENGTH { 368 return Err(RadrootsSimplexSmpProtoError::InvalidCorrelationIdLength( 369 value.len(), 370 )); 371 } 372 let mut bytes = [0_u8; Self::LENGTH]; 373 bytes.copy_from_slice(value); 374 Ok(Self(bytes)) 375 } 376 377 pub const fn as_bytes(&self) -> &[u8; 24] { 378 &self.0 379 } 380 } 381 382 #[derive(Debug, Clone, PartialEq, Eq)] 383 pub enum RadrootsSimplexSmpBrokerMessage { 384 Ids(RadrootsSimplexSmpQueueIdsResponse), 385 Lnk { 386 sender_id: Vec<u8>, 387 link_data: RadrootsSimplexSmpQueueLinkData, 388 }, 389 Sok(Option<Vec<u8>>), 390 Soks(i64), 391 Nid(RadrootsSimplexSmpNotifierIdsResponse), 392 Msg(RadrootsSimplexSmpReceivedMessage), 393 NMsg { 394 nonce: [u8; 24], 395 encrypted_metadata: Vec<u8>, 396 }, 397 PKey { 398 session_id: Vec<u8>, 399 version_range: RadrootsSimplexSmpVersionRange, 400 cert_chain_public_key: RadrootsSimplexSmpCertChainPublicKey, 401 }, 402 RRes(Vec<u8>), 403 PRes(Vec<u8>), 404 End, 405 Ends(i64), 406 Deld, 407 Info(Vec<u8>), 408 Ok, 409 Err(RadrootsSimplexSmpError), 410 Pong, 411 } 412 413 #[derive(Debug, Clone, PartialEq, Eq)] 414 pub struct RadrootsSimplexSmpCommandTransmission { 415 pub authorization: Vec<u8>, 416 pub correlation_id: Option<RadrootsSimplexSmpCorrelationId>, 417 pub entity_id: Vec<u8>, 418 pub command: RadrootsSimplexSmpCommand, 419 } 420 421 #[derive(Debug, Clone, PartialEq, Eq)] 422 pub struct RadrootsSimplexSmpBrokerTransmission { 423 pub authorization: Vec<u8>, 424 pub correlation_id: Option<RadrootsSimplexSmpCorrelationId>, 425 pub entity_id: Vec<u8>, 426 pub message: RadrootsSimplexSmpBrokerMessage, 427 } 428 429 type RadrootsSimplexSmpDecodedTransmission<'a> = ( 430 Vec<u8>, 431 Option<RadrootsSimplexSmpCorrelationId>, 432 Vec<u8>, 433 &'a [u8], 434 ); 435 436 impl RadrootsSimplexSmpCommand { 437 pub fn encode(&self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> { 438 self.encode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION) 439 } 440 441 pub fn encode_for_version( 442 &self, 443 transport_version: u16, 444 ) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> { 445 let mut buffer = Vec::new(); 446 match self { 447 Self::New(request) => encode_new_request(&mut buffer, request, transport_version)?, 448 Self::Sub => buffer.extend_from_slice(TAG_SUB), 449 Self::Subs => buffer.extend_from_slice(TAG_SUBS), 450 Self::Key(sender_auth_public_key) => { 451 buffer.extend_from_slice(TAG_KEY); 452 buffer.push(b' '); 453 push_short_bytes(&mut buffer, sender_auth_public_key)?; 454 } 455 Self::RKey(recipient_auth_public_keys) => { 456 buffer.extend_from_slice(TAG_RKEY); 457 buffer.push(b' '); 458 push_short_key_list(&mut buffer, recipient_auth_public_keys)?; 459 } 460 Self::LSet { link_id, link_data } => { 461 buffer.extend_from_slice(TAG_LSET); 462 buffer.push(b' '); 463 push_short_bytes(&mut buffer, link_id)?; 464 encode_queue_link_data(&mut buffer, link_data)?; 465 } 466 Self::LDel => buffer.extend_from_slice(TAG_LDEL), 467 Self::NKey { 468 notifier_auth_public_key, 469 recipient_notification_dh_public_key, 470 } => { 471 buffer.extend_from_slice(TAG_NKEY); 472 buffer.push(b' '); 473 push_short_bytes(&mut buffer, notifier_auth_public_key)?; 474 push_short_bytes(&mut buffer, recipient_notification_dh_public_key)?; 475 } 476 Self::NDel => buffer.extend_from_slice(TAG_NDEL), 477 Self::Get => buffer.extend_from_slice(TAG_GET), 478 Self::Ack(message_id) => { 479 buffer.extend_from_slice(TAG_ACK); 480 buffer.push(b' '); 481 push_short_bytes(&mut buffer, message_id)?; 482 } 483 Self::Off => buffer.extend_from_slice(TAG_OFF), 484 Self::Del => buffer.extend_from_slice(TAG_DEL), 485 Self::Que => buffer.extend_from_slice(TAG_QUE), 486 Self::SKey(sender_auth_public_key) => { 487 buffer.extend_from_slice(TAG_SKEY); 488 buffer.push(b' '); 489 push_short_bytes(&mut buffer, sender_auth_public_key)?; 490 } 491 Self::Send(send) => { 492 buffer.extend_from_slice(TAG_SEND); 493 buffer.push(b' '); 494 buffer.push(encode_bool(send.flags.notification)); 495 buffer.extend_from_slice(&send.flags.reserved); 496 buffer.push(b' '); 497 buffer.extend_from_slice(&send.message_body); 498 } 499 Self::Ping => buffer.extend_from_slice(TAG_PING), 500 Self::LKey(sender_auth_public_key) => { 501 buffer.extend_from_slice(TAG_LKEY); 502 buffer.push(b' '); 503 push_short_bytes(&mut buffer, sender_auth_public_key)?; 504 } 505 Self::LGet => buffer.extend_from_slice(TAG_LGET), 506 Self::NSub => buffer.extend_from_slice(TAG_NSUB), 507 Self::NSubs => buffer.extend_from_slice(TAG_NSUBS), 508 Self::Prxy { server, basic_auth } => { 509 buffer.extend_from_slice(TAG_PRXY); 510 buffer.push(b' '); 511 encode_protocol_server(&mut buffer, server)?; 512 push_maybe_string(&mut buffer, basic_auth.as_deref())?; 513 } 514 Self::PFwd { 515 relay_version, 516 public_key, 517 encrypted_transmission, 518 } => { 519 buffer.extend_from_slice(TAG_PFWD); 520 buffer.push(b' '); 521 buffer.extend_from_slice(&relay_version.to_be_bytes()); 522 push_short_bytes(&mut buffer, public_key)?; 523 buffer.extend_from_slice(encrypted_transmission); 524 } 525 Self::RFwd(encrypted_forward_transmission) => { 526 buffer.extend_from_slice(TAG_RFWD); 527 buffer.push(b' '); 528 buffer.extend_from_slice(encrypted_forward_transmission); 529 } 530 } 531 Ok(buffer) 532 } 533 534 pub fn decode(bytes: &[u8]) -> Result<Self, RadrootsSimplexSmpProtoError> { 535 Self::decode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION, bytes) 536 } 537 538 pub fn decode_for_version( 539 transport_version: u16, 540 bytes: &[u8], 541 ) -> Result<Self, RadrootsSimplexSmpProtoError> { 542 let (tag, rest) = parse_tag(bytes)?; 543 let mut cursor = Cursor::new(rest); 544 let command = match tag.as_slice() { 545 TAG_NEW => Self::New(decode_new_request(&mut cursor, transport_version)?), 546 TAG_SUB => Self::Sub, 547 TAG_SUBS => Self::Subs, 548 TAG_KEY => Self::Key(cursor.read_short_bytes()?), 549 TAG_RKEY => Self::RKey(cursor.read_short_key_list()?), 550 TAG_LSET => Self::LSet { 551 link_id: cursor.read_short_bytes()?, 552 link_data: decode_queue_link_data(&mut cursor)?, 553 }, 554 TAG_LDEL => Self::LDel, 555 TAG_NKEY => Self::NKey { 556 notifier_auth_public_key: cursor.read_short_bytes()?, 557 recipient_notification_dh_public_key: cursor.read_short_bytes()?, 558 }, 559 TAG_NDEL => Self::NDel, 560 TAG_GET => Self::Get, 561 TAG_ACK => Self::Ack(cursor.read_short_bytes()?), 562 TAG_OFF => Self::Off, 563 TAG_DEL => Self::Del, 564 TAG_QUE => Self::Que, 565 TAG_SKEY => Self::SKey(cursor.read_short_bytes()?), 566 TAG_SEND => Self::Send(decode_send_payload(rest)?), 567 TAG_PING => Self::Ping, 568 TAG_LKEY => Self::LKey(cursor.read_short_bytes()?), 569 TAG_LGET => Self::LGet, 570 TAG_NSUB => Self::NSub, 571 TAG_NSUBS => Self::NSubs, 572 TAG_PRXY => Self::Prxy { 573 server: decode_protocol_server(&mut cursor)?, 574 basic_auth: cursor.read_maybe_string()?, 575 }, 576 TAG_PFWD => Self::PFwd { 577 relay_version: u16::from_be_bytes(cursor.read_array::<2>()?), 578 public_key: cursor.read_short_bytes()?, 579 encrypted_transmission: cursor.read_remaining().to_vec(), 580 }, 581 TAG_RFWD => Self::RFwd(cursor.read_remaining().to_vec()), 582 _ => { 583 return Err(RadrootsSimplexSmpProtoError::UnsupportedTag( 584 String::from_utf8_lossy(&tag).into_owned(), 585 )); 586 } 587 }; 588 if !matches!(command, Self::Send(_)) && !cursor.is_empty() { 589 return Err(RadrootsSimplexSmpProtoError::TrailingBytes); 590 } 591 Ok(command) 592 } 593 } 594 595 impl RadrootsSimplexSmpBrokerMessage { 596 pub fn encode(&self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> { 597 self.encode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION) 598 } 599 600 pub fn encode_for_version( 601 &self, 602 transport_version: u16, 603 ) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> { 604 let mut buffer = Vec::new(); 605 match self { 606 Self::Ids(response) => encode_ids_response(&mut buffer, response, transport_version)?, 607 Self::Lnk { 608 sender_id, 609 link_data, 610 } => { 611 buffer.extend_from_slice(TAG_LNK); 612 buffer.push(b' '); 613 push_short_bytes(&mut buffer, sender_id)?; 614 encode_queue_link_data(&mut buffer, link_data)?; 615 } 616 Self::Sok(service_id) => { 617 if transport_version >= RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION { 618 buffer.extend_from_slice(TAG_SOK); 619 buffer.push(b' '); 620 push_maybe_short_bytes(&mut buffer, service_id.as_deref())?; 621 } else { 622 buffer.extend_from_slice(TAG_OK); 623 } 624 } 625 Self::Soks(queue_count) => { 626 buffer.extend_from_slice(TAG_SOKS); 627 buffer.push(b' '); 628 push_i64(&mut buffer, *queue_count); 629 } 630 Self::Nid(response) => { 631 buffer.extend_from_slice(TAG_NID); 632 buffer.push(b' '); 633 push_short_bytes(&mut buffer, &response.notifier_id)?; 634 push_short_bytes(&mut buffer, &response.server_notification_dh_public_key)?; 635 } 636 Self::Msg(message) => { 637 buffer.extend_from_slice(TAG_MSG); 638 buffer.push(b' '); 639 push_short_bytes(&mut buffer, &message.message_id)?; 640 buffer.extend_from_slice(&message.encrypted_body); 641 } 642 Self::NMsg { 643 nonce, 644 encrypted_metadata, 645 } => { 646 buffer.extend_from_slice(TAG_NMSG); 647 buffer.push(b' '); 648 buffer.extend_from_slice(nonce); 649 buffer.extend_from_slice(encrypted_metadata); 650 } 651 Self::PKey { 652 session_id, 653 version_range, 654 cert_chain_public_key, 655 } => { 656 buffer.extend_from_slice(TAG_PKEY); 657 buffer.push(b' '); 658 push_short_bytes(&mut buffer, session_id)?; 659 buffer.extend_from_slice(&version_range.min.to_be_bytes()); 660 buffer.extend_from_slice(&version_range.max.to_be_bytes()); 661 encode_cert_chain_public_key(&mut buffer, cert_chain_public_key)?; 662 } 663 Self::RRes(encrypted_forward_response) => { 664 buffer.extend_from_slice(TAG_RRES); 665 buffer.push(b' '); 666 buffer.extend_from_slice(encrypted_forward_response); 667 } 668 Self::PRes(encrypted_response) => { 669 buffer.extend_from_slice(TAG_PRES); 670 buffer.push(b' '); 671 buffer.extend_from_slice(encrypted_response); 672 } 673 Self::End => buffer.extend_from_slice(TAG_END), 674 Self::Ends(queue_count) => { 675 buffer.extend_from_slice(TAG_ENDS); 676 buffer.push(b' '); 677 push_i64(&mut buffer, *queue_count); 678 } 679 Self::Deld => buffer.extend_from_slice(TAG_DELD), 680 Self::Info(info) => { 681 buffer.extend_from_slice(TAG_INFO); 682 buffer.push(b' '); 683 buffer.extend_from_slice(info); 684 } 685 Self::Ok => buffer.extend_from_slice(TAG_OK), 686 Self::Err(error) => { 687 buffer.extend_from_slice(TAG_ERR); 688 buffer.push(b' '); 689 if transport_version < RADROOTS_SIMPLEX_SMP_BLOCKED_ENTITY_TRANSPORT_VERSION 690 && matches!(error, RadrootsSimplexSmpError::Blocked(_)) 691 { 692 buffer.extend_from_slice(b"AUTH"); 693 } else { 694 buffer.extend_from_slice(&encode_error(error)); 695 } 696 } 697 Self::Pong => buffer.extend_from_slice(TAG_PONG), 698 } 699 Ok(buffer) 700 } 701 702 pub fn decode(bytes: &[u8]) -> Result<Self, RadrootsSimplexSmpProtoError> { 703 Self::decode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION, bytes) 704 } 705 706 pub fn decode_for_version( 707 transport_version: u16, 708 bytes: &[u8], 709 ) -> Result<Self, RadrootsSimplexSmpProtoError> { 710 let (tag, rest) = parse_tag(bytes)?; 711 let mut cursor = Cursor::new(rest); 712 let message = match tag.as_slice() { 713 TAG_IDS => Self::Ids(decode_ids_response(&mut cursor, transport_version)?), 714 TAG_LNK => Self::Lnk { 715 sender_id: cursor.read_short_bytes()?, 716 link_data: decode_queue_link_data(&mut cursor)?, 717 }, 718 TAG_SOK => Self::Sok(cursor.read_maybe(Cursor::read_short_bytes)?), 719 TAG_SOKS => Self::Soks(cursor.read_i64()?), 720 TAG_NID => Self::Nid(RadrootsSimplexSmpNotifierIdsResponse { 721 notifier_id: cursor.read_short_bytes()?, 722 server_notification_dh_public_key: cursor.read_short_bytes()?, 723 }), 724 TAG_MSG => Self::Msg(RadrootsSimplexSmpReceivedMessage { 725 message_id: cursor.read_short_bytes()?, 726 encrypted_body: cursor.read_remaining().to_vec(), 727 }), 728 TAG_NMSG => { 729 let nonce = cursor.read_array::<24>().map_err(|error| match error { 730 RadrootsSimplexSmpProtoError::UnexpectedEof => { 731 RadrootsSimplexSmpProtoError::InvalidNonceLength(cursor.remaining_len()) 732 } 733 other => other, 734 })?; 735 Self::NMsg { 736 nonce, 737 encrypted_metadata: cursor.read_remaining().to_vec(), 738 } 739 } 740 TAG_PKEY => { 741 let session_id = cursor.read_short_bytes()?; 742 let min = u16::from_be_bytes(cursor.read_array::<2>()?); 743 let max = u16::from_be_bytes(cursor.read_array::<2>()?); 744 Self::PKey { 745 session_id, 746 version_range: RadrootsSimplexSmpVersionRange::new(min, max)?, 747 cert_chain_public_key: decode_cert_chain_public_key(&mut cursor)?, 748 } 749 } 750 TAG_RRES => Self::RRes(cursor.read_remaining().to_vec()), 751 TAG_PRES => Self::PRes(cursor.read_remaining().to_vec()), 752 TAG_END => Self::End, 753 TAG_ENDS => Self::Ends(cursor.read_i64()?), 754 TAG_DELD => Self::Deld, 755 TAG_INFO => Self::Info(cursor.read_remaining().to_vec()), 756 TAG_OK => Self::Ok, 757 TAG_ERR => Self::Err(decode_error(rest)?), 758 TAG_PONG => Self::Pong, 759 _ => { 760 return Err(RadrootsSimplexSmpProtoError::UnsupportedTag( 761 String::from_utf8_lossy(&tag).into_owned(), 762 )); 763 } 764 }; 765 if !matches!( 766 message, 767 Self::Msg(_) 768 | Self::NMsg { .. } 769 | Self::RRes(_) 770 | Self::PRes(_) 771 | Self::Info(_) 772 | Self::Err(_) 773 ) && !cursor.is_empty() 774 { 775 return Err(RadrootsSimplexSmpProtoError::TrailingBytes); 776 } 777 Ok(message) 778 } 779 } 780 781 impl RadrootsSimplexSmpCommandTransmission { 782 pub fn encode(&self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> { 783 self.encode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION) 784 } 785 786 pub fn encode_for_version( 787 &self, 788 transport_version: u16, 789 ) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> { 790 encode_transmission( 791 transport_version, 792 &self.authorization, 793 self.correlation_id, 794 &self.entity_id, 795 &self.command.encode_for_version(transport_version)?, 796 ) 797 } 798 799 pub fn decode(bytes: &[u8]) -> Result<Self, RadrootsSimplexSmpProtoError> { 800 Self::decode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION, bytes) 801 } 802 803 pub fn decode_for_version( 804 transport_version: u16, 805 bytes: &[u8], 806 ) -> Result<Self, RadrootsSimplexSmpProtoError> { 807 let (authorization, correlation_id, entity_id, frame) = 808 decode_transmission(transport_version, bytes)?; 809 Ok(Self { 810 authorization, 811 correlation_id, 812 entity_id, 813 command: RadrootsSimplexSmpCommand::decode_for_version(transport_version, frame)?, 814 }) 815 } 816 } 817 818 impl RadrootsSimplexSmpBrokerTransmission { 819 pub fn encode(&self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> { 820 self.encode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION) 821 } 822 823 pub fn encode_for_version( 824 &self, 825 transport_version: u16, 826 ) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> { 827 encode_transmission( 828 transport_version, 829 &self.authorization, 830 self.correlation_id, 831 &self.entity_id, 832 &self.message.encode_for_version(transport_version)?, 833 ) 834 } 835 836 pub fn decode(bytes: &[u8]) -> Result<Self, RadrootsSimplexSmpProtoError> { 837 Self::decode_for_version(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION, bytes) 838 } 839 840 pub fn decode_for_version( 841 transport_version: u16, 842 bytes: &[u8], 843 ) -> Result<Self, RadrootsSimplexSmpProtoError> { 844 let (authorization, correlation_id, entity_id, frame) = 845 decode_transmission(transport_version, bytes)?; 846 Ok(Self { 847 authorization, 848 correlation_id, 849 entity_id, 850 message: RadrootsSimplexSmpBrokerMessage::decode_for_version(transport_version, frame)?, 851 }) 852 } 853 } 854 855 fn encode_new_request( 856 buffer: &mut Vec<u8>, 857 request: &RadrootsSimplexSmpNewQueueRequest, 858 transport_version: u16, 859 ) -> Result<(), RadrootsSimplexSmpProtoError> { 860 if transport_version < RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION { 861 return Err(RadrootsSimplexSmpProtoError::UnsupportedTransportVersion( 862 transport_version, 863 )); 864 } 865 866 buffer.extend_from_slice(TAG_NEW); 867 buffer.push(b' '); 868 push_short_bytes(buffer, &request.recipient_auth_public_key)?; 869 push_short_bytes(buffer, &request.recipient_dh_public_key)?; 870 if transport_version >= RADROOTS_SIMPLEX_SMP_NEW_NOTIFIER_CREDENTIALS_TRANSPORT_VERSION { 871 push_maybe_string(buffer, request.basic_auth.as_deref())?; 872 buffer.push(encode_subscription_mode(request.subscription_mode)); 873 push_maybe( 874 buffer, 875 request.queue_request_data.as_ref(), 876 encode_queue_request_data, 877 )?; 878 push_maybe( 879 buffer, 880 request.notifier_credentials.as_ref(), 881 encode_new_notifier_credentials, 882 )?; 883 } else if transport_version >= RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION { 884 push_maybe_string(buffer, request.basic_auth.as_deref())?; 885 buffer.push(encode_subscription_mode(request.subscription_mode)); 886 push_maybe( 887 buffer, 888 request.queue_request_data.as_ref(), 889 encode_queue_request_data, 890 )?; 891 } else if transport_version >= RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION { 892 push_maybe_string(buffer, request.basic_auth.as_deref())?; 893 buffer.push(encode_subscription_mode(request.subscription_mode)); 894 buffer.push(encode_bool(request.sender_can_secure())); 895 } else { 896 push_legacy_basic_auth(buffer, request.basic_auth.as_deref())?; 897 buffer.push(encode_subscription_mode(request.subscription_mode)); 898 } 899 900 Ok(()) 901 } 902 903 fn decode_new_request( 904 cursor: &mut Cursor<'_>, 905 transport_version: u16, 906 ) -> Result<RadrootsSimplexSmpNewQueueRequest, RadrootsSimplexSmpProtoError> { 907 if transport_version < RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION { 908 return Err(RadrootsSimplexSmpProtoError::UnsupportedTransportVersion( 909 transport_version, 910 )); 911 } 912 913 let recipient_auth_public_key = cursor.read_short_bytes()?; 914 let recipient_dh_public_key = cursor.read_short_bytes()?; 915 let (basic_auth, subscription_mode, queue_request_data, notifier_credentials) = 916 if transport_version >= RADROOTS_SIMPLEX_SMP_NEW_NOTIFIER_CREDENTIALS_TRANSPORT_VERSION { 917 ( 918 cursor.read_maybe_string()?, 919 decode_subscription_mode(cursor.read_byte()?)?, 920 cursor.read_maybe(decode_queue_request_data)?, 921 cursor.read_maybe(decode_new_notifier_credentials)?, 922 ) 923 } else if transport_version >= RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION { 924 ( 925 cursor.read_maybe_string()?, 926 decode_subscription_mode(cursor.read_byte()?)?, 927 cursor.read_maybe(decode_queue_request_data)?, 928 None, 929 ) 930 } else if transport_version >= RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION { 931 let basic_auth = cursor.read_maybe_string()?; 932 let subscription_mode = decode_subscription_mode(cursor.read_byte()?)?; 933 let sender_can_secure = decode_bool(cursor.read_byte()?)?; 934 let queue_request_data = Some(if sender_can_secure { 935 RadrootsSimplexSmpQueueRequestData::Messaging(None) 936 } else { 937 RadrootsSimplexSmpQueueRequestData::Contact(None) 938 }); 939 (basic_auth, subscription_mode, queue_request_data, None) 940 } else { 941 ( 942 cursor.read_legacy_basic_auth()?, 943 decode_subscription_mode(cursor.read_byte()?)?, 944 None, 945 None, 946 ) 947 }; 948 949 Ok(RadrootsSimplexSmpNewQueueRequest { 950 recipient_auth_public_key, 951 recipient_dh_public_key, 952 basic_auth, 953 subscription_mode, 954 queue_request_data, 955 notifier_credentials, 956 }) 957 } 958 959 fn encode_ids_response( 960 buffer: &mut Vec<u8>, 961 response: &RadrootsSimplexSmpQueueIdsResponse, 962 transport_version: u16, 963 ) -> Result<(), RadrootsSimplexSmpProtoError> { 964 buffer.extend_from_slice(TAG_IDS); 965 buffer.push(b' '); 966 push_short_bytes(buffer, &response.recipient_id)?; 967 push_short_bytes(buffer, &response.sender_id)?; 968 push_short_bytes(buffer, &response.server_dh_public_key)?; 969 970 if transport_version >= RADROOTS_SIMPLEX_SMP_NEW_NOTIFIER_CREDENTIALS_TRANSPORT_VERSION { 971 push_maybe(buffer, response.queue_mode, encode_queue_mode)?; 972 push_maybe_short_bytes(buffer, response.link_id.as_deref())?; 973 push_maybe_short_bytes(buffer, response.service_id.as_deref())?; 974 push_maybe( 975 buffer, 976 response.server_notification_credentials.as_ref(), 977 encode_server_notifier_credentials, 978 )?; 979 } else if transport_version >= RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION { 980 push_maybe(buffer, response.queue_mode, encode_queue_mode)?; 981 push_maybe_short_bytes(buffer, response.link_id.as_deref())?; 982 push_maybe_short_bytes(buffer, response.service_id.as_deref())?; 983 } else if transport_version >= RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION { 984 push_maybe(buffer, response.queue_mode, encode_queue_mode)?; 985 push_maybe_short_bytes(buffer, response.link_id.as_deref())?; 986 } else if transport_version >= RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION { 987 buffer.push(encode_bool(response.sender_can_secure())); 988 } 989 990 Ok(()) 991 } 992 993 fn decode_ids_response( 994 cursor: &mut Cursor<'_>, 995 transport_version: u16, 996 ) -> Result<RadrootsSimplexSmpQueueIdsResponse, RadrootsSimplexSmpProtoError> { 997 let recipient_id = cursor.read_short_bytes()?; 998 let sender_id = cursor.read_short_bytes()?; 999 let server_dh_public_key = cursor.read_short_bytes()?; 1000 1001 let (queue_mode, link_id, service_id, server_notification_credentials) = 1002 if transport_version >= RADROOTS_SIMPLEX_SMP_NEW_NOTIFIER_CREDENTIALS_TRANSPORT_VERSION { 1003 ( 1004 cursor.read_maybe(decode_queue_mode)?, 1005 cursor.read_maybe(Cursor::read_short_bytes)?, 1006 cursor.read_maybe(Cursor::read_short_bytes)?, 1007 cursor.read_maybe(decode_server_notifier_credentials)?, 1008 ) 1009 } else if transport_version >= RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION { 1010 ( 1011 cursor.read_maybe(decode_queue_mode)?, 1012 cursor.read_maybe(Cursor::read_short_bytes)?, 1013 cursor.read_maybe(Cursor::read_short_bytes)?, 1014 None, 1015 ) 1016 } else if transport_version >= RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION { 1017 ( 1018 cursor.read_maybe(decode_queue_mode)?, 1019 cursor.read_maybe(Cursor::read_short_bytes)?, 1020 None, 1021 None, 1022 ) 1023 } else if transport_version >= RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION { 1024 let sender_can_secure = decode_bool(cursor.read_byte()?)?; 1025 ( 1026 Some(if sender_can_secure { 1027 RadrootsSimplexSmpQueueMode::Messaging 1028 } else { 1029 RadrootsSimplexSmpQueueMode::Contact 1030 }), 1031 None, 1032 None, 1033 None, 1034 ) 1035 } else { 1036 (None, None, None, None) 1037 }; 1038 1039 Ok(RadrootsSimplexSmpQueueIdsResponse { 1040 recipient_id, 1041 sender_id, 1042 server_dh_public_key, 1043 queue_mode, 1044 link_id, 1045 service_id, 1046 server_notification_credentials, 1047 }) 1048 } 1049 1050 fn encode_queue_request_data( 1051 buffer: &mut Vec<u8>, 1052 queue_request_data: &RadrootsSimplexSmpQueueRequestData, 1053 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1054 match queue_request_data { 1055 RadrootsSimplexSmpQueueRequestData::Messaging(data) => { 1056 buffer.push(b'M'); 1057 push_maybe(buffer, data.as_ref(), encode_messaging_queue_request) 1058 } 1059 RadrootsSimplexSmpQueueRequestData::Contact(data) => { 1060 buffer.push(b'C'); 1061 push_maybe(buffer, data.as_ref(), encode_contact_queue_request) 1062 } 1063 } 1064 } 1065 1066 fn decode_queue_request_data( 1067 cursor: &mut Cursor<'_>, 1068 ) -> Result<RadrootsSimplexSmpQueueRequestData, RadrootsSimplexSmpProtoError> { 1069 match cursor.read_byte()? { 1070 b'M' => Ok(RadrootsSimplexSmpQueueRequestData::Messaging( 1071 cursor.read_maybe(decode_messaging_queue_request)?, 1072 )), 1073 b'C' => Ok(RadrootsSimplexSmpQueueRequestData::Contact( 1074 cursor.read_maybe(decode_contact_queue_request)?, 1075 )), 1076 value => Err(RadrootsSimplexSmpProtoError::InvalidTag( 1077 String::from_utf8_lossy(&[value]).into_owned(), 1078 )), 1079 } 1080 } 1081 1082 fn encode_messaging_queue_request( 1083 buffer: &mut Vec<u8>, 1084 request: &RadrootsSimplexSmpMessagingQueueRequest, 1085 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1086 push_short_bytes(buffer, &request.sender_id)?; 1087 encode_queue_link_data(buffer, &request.link_data) 1088 } 1089 1090 fn decode_messaging_queue_request( 1091 cursor: &mut Cursor<'_>, 1092 ) -> Result<RadrootsSimplexSmpMessagingQueueRequest, RadrootsSimplexSmpProtoError> { 1093 Ok(RadrootsSimplexSmpMessagingQueueRequest { 1094 sender_id: cursor.read_short_bytes()?, 1095 link_data: decode_queue_link_data(cursor)?, 1096 }) 1097 } 1098 1099 fn encode_contact_queue_request( 1100 buffer: &mut Vec<u8>, 1101 request: &RadrootsSimplexSmpContactQueueRequest, 1102 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1103 push_short_bytes(buffer, &request.link_id)?; 1104 push_short_bytes(buffer, &request.sender_id)?; 1105 encode_queue_link_data(buffer, &request.link_data) 1106 } 1107 1108 fn decode_contact_queue_request( 1109 cursor: &mut Cursor<'_>, 1110 ) -> Result<RadrootsSimplexSmpContactQueueRequest, RadrootsSimplexSmpProtoError> { 1111 Ok(RadrootsSimplexSmpContactQueueRequest { 1112 link_id: cursor.read_short_bytes()?, 1113 sender_id: cursor.read_short_bytes()?, 1114 link_data: decode_queue_link_data(cursor)?, 1115 }) 1116 } 1117 1118 fn encode_protocol_server( 1119 buffer: &mut Vec<u8>, 1120 server: &RadrootsSimplexSmpProtocolServer, 1121 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1122 validate_transport_hosts(&server.hosts)?; 1123 push_short_string_list(buffer, &server.hosts)?; 1124 push_short_string(buffer, &server.port)?; 1125 push_short_bytes(buffer, &server.key_hash) 1126 } 1127 1128 fn decode_protocol_server( 1129 cursor: &mut Cursor<'_>, 1130 ) -> Result<RadrootsSimplexSmpProtocolServer, RadrootsSimplexSmpProtoError> { 1131 let hosts = cursor.read_short_string_list()?; 1132 validate_transport_hosts(&hosts)?; 1133 Ok(RadrootsSimplexSmpProtocolServer { 1134 hosts, 1135 port: cursor.read_short_string_lossy()?, 1136 key_hash: cursor.read_short_bytes()?, 1137 }) 1138 } 1139 1140 fn encode_cert_chain_public_key( 1141 buffer: &mut Vec<u8>, 1142 cert_chain_public_key: &RadrootsSimplexSmpCertChainPublicKey, 1143 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1144 push_large_bytes_list(buffer, &cert_chain_public_key.certificate_chain)?; 1145 push_large_bytes(buffer, &cert_chain_public_key.signed_public_key) 1146 } 1147 1148 fn decode_cert_chain_public_key( 1149 cursor: &mut Cursor<'_>, 1150 ) -> Result<RadrootsSimplexSmpCertChainPublicKey, RadrootsSimplexSmpProtoError> { 1151 Ok(RadrootsSimplexSmpCertChainPublicKey { 1152 certificate_chain: cursor.read_large_bytes_list()?, 1153 signed_public_key: cursor.read_large_bytes()?, 1154 }) 1155 } 1156 1157 fn encode_queue_link_data( 1158 buffer: &mut Vec<u8>, 1159 link_data: &RadrootsSimplexSmpQueueLinkData, 1160 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1161 push_large_bytes(buffer, &link_data.fixed_data)?; 1162 push_large_bytes(buffer, &link_data.user_data) 1163 } 1164 1165 fn decode_queue_link_data( 1166 cursor: &mut Cursor<'_>, 1167 ) -> Result<RadrootsSimplexSmpQueueLinkData, RadrootsSimplexSmpProtoError> { 1168 Ok(RadrootsSimplexSmpQueueLinkData { 1169 fixed_data: cursor.read_large_bytes()?, 1170 user_data: cursor.read_large_bytes()?, 1171 }) 1172 } 1173 1174 fn encode_new_notifier_credentials( 1175 buffer: &mut Vec<u8>, 1176 credentials: &RadrootsSimplexSmpNewNotifierCredentials, 1177 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1178 push_short_bytes(buffer, &credentials.notifier_auth_public_key)?; 1179 push_short_bytes(buffer, &credentials.recipient_notification_dh_public_key) 1180 } 1181 1182 fn decode_new_notifier_credentials( 1183 cursor: &mut Cursor<'_>, 1184 ) -> Result<RadrootsSimplexSmpNewNotifierCredentials, RadrootsSimplexSmpProtoError> { 1185 Ok(RadrootsSimplexSmpNewNotifierCredentials { 1186 notifier_auth_public_key: cursor.read_short_bytes()?, 1187 recipient_notification_dh_public_key: cursor.read_short_bytes()?, 1188 }) 1189 } 1190 1191 fn encode_server_notifier_credentials( 1192 buffer: &mut Vec<u8>, 1193 credentials: &RadrootsSimplexSmpServerNotifierCredentials, 1194 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1195 push_short_bytes(buffer, &credentials.notifier_id)?; 1196 push_short_bytes(buffer, &credentials.server_notification_dh_public_key) 1197 } 1198 1199 fn decode_server_notifier_credentials( 1200 cursor: &mut Cursor<'_>, 1201 ) -> Result<RadrootsSimplexSmpServerNotifierCredentials, RadrootsSimplexSmpProtoError> { 1202 Ok(RadrootsSimplexSmpServerNotifierCredentials { 1203 notifier_id: cursor.read_short_bytes()?, 1204 server_notification_dh_public_key: cursor.read_short_bytes()?, 1205 }) 1206 } 1207 1208 fn encode_queue_mode( 1209 buffer: &mut Vec<u8>, 1210 queue_mode: RadrootsSimplexSmpQueueMode, 1211 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1212 buffer.push(match queue_mode { 1213 RadrootsSimplexSmpQueueMode::Messaging => b'M', 1214 RadrootsSimplexSmpQueueMode::Contact => b'C', 1215 }); 1216 Ok(()) 1217 } 1218 1219 fn decode_queue_mode( 1220 cursor: &mut Cursor<'_>, 1221 ) -> Result<RadrootsSimplexSmpQueueMode, RadrootsSimplexSmpProtoError> { 1222 match cursor.read_byte()? { 1223 b'M' => Ok(RadrootsSimplexSmpQueueMode::Messaging), 1224 b'C' => Ok(RadrootsSimplexSmpQueueMode::Contact), 1225 value => Err(RadrootsSimplexSmpProtoError::InvalidTag( 1226 String::from_utf8_lossy(&[value]).into_owned(), 1227 )), 1228 } 1229 } 1230 1231 fn validate_transport_hosts(hosts: &[String]) -> Result<(), RadrootsSimplexSmpProtoError> { 1232 for host in hosts { 1233 validate_transport_host(host)?; 1234 } 1235 Ok(()) 1236 } 1237 1238 fn validate_transport_host(host: &str) -> Result<(), RadrootsSimplexSmpProtoError> { 1239 if is_valid_ipv4_transport_host(host) 1240 || is_valid_ipv6_transport_host(host) 1241 || is_valid_onion_transport_host(host) 1242 || is_valid_domain_transport_host(host) 1243 { 1244 return Ok(()); 1245 } 1246 Err(RadrootsSimplexSmpProtoError::InvalidHostList( 1247 host.to_string(), 1248 )) 1249 } 1250 1251 fn is_valid_ipv4_transport_host(host: &str) -> bool { 1252 let mut segments = 0_usize; 1253 for segment in host.split('.') { 1254 if segment.is_empty() || !segment.bytes().all(|byte| byte.is_ascii_digit()) { 1255 return false; 1256 } 1257 if segment.parse::<u16>().map_or(true, |value| value > 255) { 1258 return false; 1259 } 1260 segments += 1; 1261 } 1262 segments == 4 1263 } 1264 1265 fn is_valid_ipv6_transport_host(host: &str) -> bool { 1266 let candidate = if let Some(stripped) = host.strip_prefix('[') { 1267 let Some(inner) = stripped.strip_suffix(']') else { 1268 return false; 1269 }; 1270 inner 1271 } else { 1272 if host.ends_with(']') { 1273 return false; 1274 } 1275 host 1276 }; 1277 if candidate.is_empty() 1278 || !candidate 1279 .bytes() 1280 .all(|byte| byte.is_ascii_hexdigit() || byte == b':') 1281 { 1282 return false; 1283 } 1284 Ipv6Addr::from_str(candidate).is_ok() 1285 } 1286 1287 fn is_valid_onion_transport_host(host: &str) -> bool { 1288 let Some(prefix) = host.strip_suffix(".onion") else { 1289 return false; 1290 }; 1291 !prefix.is_empty() 1292 && prefix 1293 .bytes() 1294 .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit()) 1295 } 1296 1297 fn is_valid_domain_transport_host(host: &str) -> bool { 1298 !host.is_empty() 1299 && !host.ends_with(".onion") 1300 && !host.starts_with('[') 1301 && !host.ends_with(']') 1302 && !host.contains(':') 1303 && host 1304 .chars() 1305 .all(|character| !matches!(character, '#' | ',' | ';' | '/' | ' ' | '\n' | '\r' | '\t')) 1306 } 1307 1308 fn encode_transmission( 1309 transport_version: u16, 1310 authorization: &[u8], 1311 correlation_id: Option<RadrootsSimplexSmpCorrelationId>, 1312 entity_id: &[u8], 1313 frame: &[u8], 1314 ) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> { 1315 let mut buffer = Vec::new(); 1316 push_short_bytes(&mut buffer, authorization)?; 1317 if transport_version >= RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION 1318 && !authorization.is_empty() 1319 { 1320 push_maybe_short_bytes(&mut buffer, None)?; 1321 } 1322 push_short_bytes( 1323 &mut buffer, 1324 correlation_id 1325 .map(|id| id.0.to_vec()) 1326 .as_deref() 1327 .unwrap_or_default(), 1328 )?; 1329 push_short_bytes(&mut buffer, entity_id)?; 1330 buffer.extend_from_slice(frame); 1331 Ok(buffer) 1332 } 1333 1334 fn decode_transmission( 1335 transport_version: u16, 1336 bytes: &[u8], 1337 ) -> Result<RadrootsSimplexSmpDecodedTransmission<'_>, RadrootsSimplexSmpProtoError> { 1338 let mut cursor = Cursor::new(bytes); 1339 let authorization = cursor.read_short_bytes()?; 1340 if transport_version >= RADROOTS_SIMPLEX_SMP_SERVICE_CERTS_TRANSPORT_VERSION 1341 && !authorization.is_empty() 1342 { 1343 let _ = cursor.read_maybe(Cursor::read_short_bytes)?; 1344 } 1345 let correlation_id = match cursor.read_short_bytes()?.as_slice() { 1346 [] => None, 1347 value => Some(RadrootsSimplexSmpCorrelationId::from_slice(value)?), 1348 }; 1349 let entity_id = cursor.read_short_bytes()?; 1350 let frame = cursor.read_remaining(); 1351 if frame.is_empty() { 1352 return Err(RadrootsSimplexSmpProtoError::UnexpectedEof); 1353 } 1354 Ok((authorization, correlation_id, entity_id, frame)) 1355 } 1356 1357 fn decode_send_payload( 1358 payload: &[u8], 1359 ) -> Result<RadrootsSimplexSmpSendCommand, RadrootsSimplexSmpProtoError> { 1360 let Some(space_index) = payload.iter().position(|byte| *byte == b' ') else { 1361 return Err(RadrootsSimplexSmpProtoError::UnexpectedEof); 1362 }; 1363 let flags_bytes = &payload[..space_index]; 1364 if flags_bytes.is_empty() { 1365 return Err(RadrootsSimplexSmpProtoError::MissingField("msg_flags")); 1366 } 1367 let flags = RadrootsSimplexSmpMessageFlags { 1368 notification: decode_bool(flags_bytes[0])?, 1369 reserved: flags_bytes[1..].to_vec(), 1370 }; 1371 Ok(RadrootsSimplexSmpSendCommand { 1372 flags, 1373 message_body: payload[space_index + 1..].to_vec(), 1374 }) 1375 } 1376 1377 fn encode_error(error: &RadrootsSimplexSmpError) -> Vec<u8> { 1378 match error { 1379 RadrootsSimplexSmpError::Block => b"BLOCK".to_vec(), 1380 RadrootsSimplexSmpError::Session => b"SESSION".to_vec(), 1381 RadrootsSimplexSmpError::Command(command_error) => { 1382 let mut bytes = b"CMD ".to_vec(); 1383 bytes.extend_from_slice(match command_error { 1384 RadrootsSimplexSmpCommandError::Unknown => COMMAND_ERR_UNKNOWN, 1385 RadrootsSimplexSmpCommandError::Syntax => COMMAND_ERR_SYNTAX, 1386 RadrootsSimplexSmpCommandError::Prohibited => COMMAND_ERR_PROHIBITED, 1387 RadrootsSimplexSmpCommandError::NoAuth => COMMAND_ERR_NO_AUTH, 1388 RadrootsSimplexSmpCommandError::HasAuth => COMMAND_ERR_HAS_AUTH, 1389 RadrootsSimplexSmpCommandError::NoEntity => COMMAND_ERR_NO_ENTITY, 1390 RadrootsSimplexSmpCommandError::Other(raw) => raw, 1391 }); 1392 bytes 1393 } 1394 RadrootsSimplexSmpError::Proxy(proxy_error) => { 1395 let mut bytes = b"PROXY ".to_vec(); 1396 bytes.extend_from_slice(&encode_proxy_error(proxy_error)); 1397 bytes 1398 } 1399 RadrootsSimplexSmpError::Auth => b"AUTH".to_vec(), 1400 RadrootsSimplexSmpError::Blocked(blocking_info) => { 1401 let mut bytes = b"BLOCKED ".to_vec(); 1402 bytes.extend_from_slice(&encode_blocking_info(blocking_info)); 1403 bytes 1404 } 1405 RadrootsSimplexSmpError::Service => b"SERVICE".to_vec(), 1406 RadrootsSimplexSmpError::Crypto => b"CRYPTO".to_vec(), 1407 RadrootsSimplexSmpError::Quota => b"QUOTA".to_vec(), 1408 RadrootsSimplexSmpError::Store(store_error) => { 1409 let mut bytes = b"STORE ".to_vec(); 1410 bytes.extend_from_slice(store_error.as_bytes()); 1411 bytes 1412 } 1413 RadrootsSimplexSmpError::NoMsg => b"NO_MSG".to_vec(), 1414 RadrootsSimplexSmpError::LargeMsg => b"LARGE_MSG".to_vec(), 1415 RadrootsSimplexSmpError::Expired => b"EXPIRED".to_vec(), 1416 RadrootsSimplexSmpError::Internal => b"INTERNAL".to_vec(), 1417 RadrootsSimplexSmpError::Duplicate => b"DUPLICATE_".to_vec(), 1418 RadrootsSimplexSmpError::Other(raw) => raw.clone(), 1419 } 1420 } 1421 1422 fn decode_error(bytes: &[u8]) -> Result<RadrootsSimplexSmpError, RadrootsSimplexSmpProtoError> { 1423 if bytes == b"BLOCK" { 1424 return Ok(RadrootsSimplexSmpError::Block); 1425 } 1426 if bytes == b"SESSION" { 1427 return Ok(RadrootsSimplexSmpError::Session); 1428 } 1429 if bytes == b"AUTH" { 1430 return Ok(RadrootsSimplexSmpError::Auth); 1431 } 1432 if bytes == b"SERVICE" { 1433 return Ok(RadrootsSimplexSmpError::Service); 1434 } 1435 if bytes == b"CRYPTO" { 1436 return Ok(RadrootsSimplexSmpError::Crypto); 1437 } 1438 if bytes == b"QUOTA" { 1439 return Ok(RadrootsSimplexSmpError::Quota); 1440 } 1441 if let Some(store_error) = bytes.strip_prefix(b"STORE ") { 1442 return Ok(RadrootsSimplexSmpError::Store( 1443 String::from_utf8_lossy(store_error).into_owned(), 1444 )); 1445 } 1446 if bytes == b"NO_MSG" { 1447 return Ok(RadrootsSimplexSmpError::NoMsg); 1448 } 1449 if bytes == b"LARGE_MSG" { 1450 return Ok(RadrootsSimplexSmpError::LargeMsg); 1451 } 1452 if bytes == b"EXPIRED" { 1453 return Ok(RadrootsSimplexSmpError::Expired); 1454 } 1455 if bytes == b"INTERNAL" { 1456 return Ok(RadrootsSimplexSmpError::Internal); 1457 } 1458 if bytes == b"DUPLICATE_" { 1459 return Ok(RadrootsSimplexSmpError::Duplicate); 1460 } 1461 if let Some(command) = bytes.strip_prefix(b"CMD ") { 1462 let command_error = match command { 1463 COMMAND_ERR_UNKNOWN => RadrootsSimplexSmpCommandError::Unknown, 1464 COMMAND_ERR_SYNTAX => RadrootsSimplexSmpCommandError::Syntax, 1465 COMMAND_ERR_PROHIBITED => RadrootsSimplexSmpCommandError::Prohibited, 1466 COMMAND_ERR_NO_AUTH => RadrootsSimplexSmpCommandError::NoAuth, 1467 COMMAND_ERR_HAS_AUTH => RadrootsSimplexSmpCommandError::HasAuth, 1468 COMMAND_ERR_NO_ENTITY | COMMAND_ERR_NO_QUEUE => { 1469 RadrootsSimplexSmpCommandError::NoEntity 1470 } 1471 raw => RadrootsSimplexSmpCommandError::Other(raw.to_vec()), 1472 }; 1473 return Ok(RadrootsSimplexSmpError::Command(command_error)); 1474 } 1475 if let Some(proxy_error) = bytes.strip_prefix(b"PROXY ") { 1476 return Ok(RadrootsSimplexSmpError::Proxy(decode_proxy_error( 1477 proxy_error, 1478 )?)); 1479 } 1480 if let Some(blocking_info) = bytes.strip_prefix(b"BLOCKED ") { 1481 return Ok(RadrootsSimplexSmpError::Blocked(decode_blocking_info( 1482 blocking_info, 1483 )?)); 1484 } 1485 Ok(RadrootsSimplexSmpError::Other(bytes.to_vec())) 1486 } 1487 1488 fn encode_proxy_error(error: &RadrootsSimplexSmpProxyError) -> Vec<u8> { 1489 match error { 1490 RadrootsSimplexSmpProxyError::Protocol(error) => { 1491 let mut bytes = b"PROTOCOL ".to_vec(); 1492 bytes.extend_from_slice(&encode_error(error)); 1493 bytes 1494 } 1495 RadrootsSimplexSmpProxyError::Broker(error) => { 1496 let mut bytes = b"BROKER ".to_vec(); 1497 bytes.extend_from_slice(&encode_broker_error(error)); 1498 bytes 1499 } 1500 RadrootsSimplexSmpProxyError::BasicAuth => b"BASIC_AUTH".to_vec(), 1501 RadrootsSimplexSmpProxyError::NoSession => b"NO_SESSION".to_vec(), 1502 } 1503 } 1504 1505 fn decode_proxy_error( 1506 bytes: &[u8], 1507 ) -> Result<RadrootsSimplexSmpProxyError, RadrootsSimplexSmpProtoError> { 1508 let (tag, rest) = parse_tag(bytes)?; 1509 match tag.as_slice() { 1510 b"PROTOCOL" => Ok(RadrootsSimplexSmpProxyError::Protocol(Box::new( 1511 decode_error(rest)?, 1512 ))), 1513 b"BROKER" => Ok(RadrootsSimplexSmpProxyError::Broker(decode_broker_error( 1514 rest, 1515 )?)), 1516 b"BASIC_AUTH" if rest.is_empty() => Ok(RadrootsSimplexSmpProxyError::BasicAuth), 1517 b"NO_SESSION" if rest.is_empty() => Ok(RadrootsSimplexSmpProxyError::NoSession), 1518 _ => Err(invalid_ascii_tag(&tag)), 1519 } 1520 } 1521 1522 fn encode_broker_error(error: &RadrootsSimplexSmpBrokerError) -> Vec<u8> { 1523 match error { 1524 RadrootsSimplexSmpBrokerError::Response(response_error) => { 1525 let mut bytes = b"RESPONSE ".to_vec(); 1526 push_short_string(&mut bytes, response_error) 1527 .expect("response_error length is bounded by SMP short-string encoding"); 1528 bytes 1529 } 1530 RadrootsSimplexSmpBrokerError::Unexpected(response_error) => { 1531 let mut bytes = b"UNEXPECTED ".to_vec(); 1532 push_short_string(&mut bytes, response_error) 1533 .expect("response_error length is bounded by SMP short-string encoding"); 1534 bytes 1535 } 1536 RadrootsSimplexSmpBrokerError::Network(_) => b"NETWORK".to_vec(), 1537 RadrootsSimplexSmpBrokerError::Host => b"HOST".to_vec(), 1538 RadrootsSimplexSmpBrokerError::NoService => b"NO_SERVICE".to_vec(), 1539 RadrootsSimplexSmpBrokerError::Transport(error) => { 1540 let mut bytes = b"TRANSPORT ".to_vec(); 1541 bytes.extend_from_slice(&encode_transport_error(error)); 1542 bytes 1543 } 1544 RadrootsSimplexSmpBrokerError::Timeout => b"TIMEOUT".to_vec(), 1545 } 1546 } 1547 1548 fn decode_broker_error( 1549 bytes: &[u8], 1550 ) -> Result<RadrootsSimplexSmpBrokerError, RadrootsSimplexSmpProtoError> { 1551 let (tag, rest) = parse_tag(bytes)?; 1552 match tag.as_slice() { 1553 b"RESPONSE" => Ok(RadrootsSimplexSmpBrokerError::Response( 1554 decode_short_string_lossy(rest)?, 1555 )), 1556 b"UNEXPECTED" => Ok(RadrootsSimplexSmpBrokerError::Unexpected( 1557 decode_short_string_lossy(rest)?, 1558 )), 1559 b"TRANSPORT" => Ok(RadrootsSimplexSmpBrokerError::Transport( 1560 decode_transport_error(rest)?, 1561 )), 1562 b"NETWORK" if rest.is_empty() => Ok(RadrootsSimplexSmpBrokerError::Network( 1563 RadrootsSimplexSmpNetworkError::Failed, 1564 )), 1565 b"NETWORK" => Ok(RadrootsSimplexSmpBrokerError::Network( 1566 decode_network_error(rest)?, 1567 )), 1568 b"TIMEOUT" if rest.is_empty() => Ok(RadrootsSimplexSmpBrokerError::Timeout), 1569 b"HOST" if rest.is_empty() => Ok(RadrootsSimplexSmpBrokerError::Host), 1570 b"NO_SERVICE" if rest.is_empty() => Ok(RadrootsSimplexSmpBrokerError::NoService), 1571 _ => Err(invalid_ascii_tag(&tag)), 1572 } 1573 } 1574 1575 fn encode_transport_error(error: &RadrootsSimplexSmpTransportError) -> Vec<u8> { 1576 match error { 1577 RadrootsSimplexSmpTransportError::Block => b"BLOCK".to_vec(), 1578 RadrootsSimplexSmpTransportError::Version => b"VERSION".to_vec(), 1579 RadrootsSimplexSmpTransportError::LargeMsg => b"LARGE_MSG".to_vec(), 1580 RadrootsSimplexSmpTransportError::Session => b"SESSION".to_vec(), 1581 RadrootsSimplexSmpTransportError::NoAuth => b"NO_AUTH".to_vec(), 1582 RadrootsSimplexSmpTransportError::Handshake(error) => { 1583 let mut bytes = b"HANDSHAKE ".to_vec(); 1584 bytes.extend_from_slice(&encode_handshake_error(error)); 1585 bytes 1586 } 1587 } 1588 } 1589 1590 fn decode_transport_error( 1591 bytes: &[u8], 1592 ) -> Result<RadrootsSimplexSmpTransportError, RadrootsSimplexSmpProtoError> { 1593 let (tag, rest) = parse_tag(bytes)?; 1594 match tag.as_slice() { 1595 b"BLOCK" if rest.is_empty() => Ok(RadrootsSimplexSmpTransportError::Block), 1596 b"VERSION" if rest.is_empty() => Ok(RadrootsSimplexSmpTransportError::Version), 1597 b"LARGE_MSG" if rest.is_empty() => Ok(RadrootsSimplexSmpTransportError::LargeMsg), 1598 b"SESSION" if rest.is_empty() => Ok(RadrootsSimplexSmpTransportError::Session), 1599 b"NO_AUTH" if rest.is_empty() => Ok(RadrootsSimplexSmpTransportError::NoAuth), 1600 b"HANDSHAKE" => Ok(RadrootsSimplexSmpTransportError::Handshake( 1601 decode_handshake_error(rest)?, 1602 )), 1603 _ => Err(invalid_ascii_tag(&tag)), 1604 } 1605 } 1606 1607 #[cfg(test)] 1608 fn encode_network_error(error: &RadrootsSimplexSmpNetworkError) -> Vec<u8> { 1609 match error { 1610 RadrootsSimplexSmpNetworkError::Connect(connect_error) => { 1611 let mut bytes = b"CONNECT ".to_vec(); 1612 push_short_string(&mut bytes, connect_error) 1613 .expect("connect_error length is bounded by SMP short-string encoding"); 1614 bytes 1615 } 1616 RadrootsSimplexSmpNetworkError::Tls(tls_error) => { 1617 let mut bytes = b"TLS ".to_vec(); 1618 push_short_string(&mut bytes, tls_error) 1619 .expect("tls_error length is bounded by SMP short-string encoding"); 1620 bytes 1621 } 1622 RadrootsSimplexSmpNetworkError::UnknownCa => b"UNKNOWNCA".to_vec(), 1623 RadrootsSimplexSmpNetworkError::Failed => b"FAILED".to_vec(), 1624 RadrootsSimplexSmpNetworkError::Timeout => b"TIMEOUT".to_vec(), 1625 RadrootsSimplexSmpNetworkError::Subscribe(subscribe_error) => { 1626 let mut bytes = b"SUBSCRIBE ".to_vec(); 1627 push_short_string(&mut bytes, subscribe_error) 1628 .expect("subscribe_error length is bounded by SMP short-string encoding"); 1629 bytes 1630 } 1631 } 1632 } 1633 1634 fn decode_network_error( 1635 bytes: &[u8], 1636 ) -> Result<RadrootsSimplexSmpNetworkError, RadrootsSimplexSmpProtoError> { 1637 let (tag, rest) = parse_tag(bytes)?; 1638 match tag.as_slice() { 1639 b"CONNECT" => Ok(RadrootsSimplexSmpNetworkError::Connect( 1640 decode_short_string_lossy(rest)?, 1641 )), 1642 b"TLS" => Ok(RadrootsSimplexSmpNetworkError::Tls( 1643 decode_short_string_lossy(rest)?, 1644 )), 1645 b"UNKNOWNCA" if rest.is_empty() => Ok(RadrootsSimplexSmpNetworkError::UnknownCa), 1646 b"FAILED" if rest.is_empty() => Ok(RadrootsSimplexSmpNetworkError::Failed), 1647 b"TIMEOUT" if rest.is_empty() => Ok(RadrootsSimplexSmpNetworkError::Timeout), 1648 b"SUBSCRIBE" => Ok(RadrootsSimplexSmpNetworkError::Subscribe( 1649 decode_short_string_lossy(rest)?, 1650 )), 1651 _ => Err(invalid_ascii_tag(&tag)), 1652 } 1653 } 1654 1655 fn encode_handshake_error(error: &RadrootsSimplexSmpHandshakeError) -> Vec<u8> { 1656 match error { 1657 RadrootsSimplexSmpHandshakeError::Parse => b"PARSE".to_vec(), 1658 RadrootsSimplexSmpHandshakeError::Identity => b"IDENTITY".to_vec(), 1659 RadrootsSimplexSmpHandshakeError::BadAuth => b"BAD_AUTH".to_vec(), 1660 RadrootsSimplexSmpHandshakeError::BadService => b"BAD_SERVICE".to_vec(), 1661 RadrootsSimplexSmpHandshakeError::Other(raw) => raw.as_bytes().to_vec(), 1662 } 1663 } 1664 1665 fn decode_handshake_error( 1666 bytes: &[u8], 1667 ) -> Result<RadrootsSimplexSmpHandshakeError, RadrootsSimplexSmpProtoError> { 1668 match bytes { 1669 b"PARSE" => Ok(RadrootsSimplexSmpHandshakeError::Parse), 1670 b"IDENTITY" => Ok(RadrootsSimplexSmpHandshakeError::Identity), 1671 b"BAD_AUTH" => Ok(RadrootsSimplexSmpHandshakeError::BadAuth), 1672 b"BAD_SERVICE" => Ok(RadrootsSimplexSmpHandshakeError::BadService), 1673 raw => Err(invalid_ascii_tag(raw)), 1674 } 1675 } 1676 1677 fn encode_blocking_info(info: &RadrootsSimplexSmpBlockingInfo) -> Vec<u8> { 1678 let mut bytes = b"reason=".to_vec(); 1679 bytes.extend_from_slice(match &info.reason { 1680 RadrootsSimplexSmpBlockingReason::Spam => b"spam", 1681 RadrootsSimplexSmpBlockingReason::Content => b"content", 1682 RadrootsSimplexSmpBlockingReason::Other(reason) => reason.as_bytes(), 1683 }); 1684 bytes 1685 } 1686 1687 fn decode_blocking_info( 1688 bytes: &[u8], 1689 ) -> Result<RadrootsSimplexSmpBlockingInfo, RadrootsSimplexSmpProtoError> { 1690 let Some(reason) = bytes.strip_prefix(b"reason=") else { 1691 return Err(invalid_ascii_tag(bytes)); 1692 }; 1693 let reason = match reason { 1694 b"spam" => RadrootsSimplexSmpBlockingReason::Spam, 1695 b"content" => RadrootsSimplexSmpBlockingReason::Content, 1696 raw => return Err(invalid_ascii_tag(raw)), 1697 }; 1698 Ok(RadrootsSimplexSmpBlockingInfo { reason }) 1699 } 1700 1701 fn decode_short_string_lossy(bytes: &[u8]) -> Result<String, RadrootsSimplexSmpProtoError> { 1702 let mut cursor = Cursor::new(bytes); 1703 let value = cursor.read_short_string_lossy()?; 1704 if !cursor.is_empty() { 1705 return Err(RadrootsSimplexSmpProtoError::TrailingBytes); 1706 } 1707 Ok(value) 1708 } 1709 1710 fn invalid_ascii_tag(bytes: &[u8]) -> RadrootsSimplexSmpProtoError { 1711 RadrootsSimplexSmpProtoError::InvalidTag(String::from_utf8_lossy(bytes).into_owned()) 1712 } 1713 1714 fn parse_tag(bytes: &[u8]) -> Result<(Vec<u8>, &[u8]), RadrootsSimplexSmpProtoError> { 1715 if bytes.is_empty() { 1716 return Err(RadrootsSimplexSmpProtoError::UnexpectedEof); 1717 } 1718 if let Some(space_index) = bytes.iter().position(|byte| *byte == b' ') { 1719 Ok((bytes[..space_index].to_vec(), &bytes[space_index + 1..])) 1720 } else { 1721 Ok((bytes.to_vec(), &[])) 1722 } 1723 } 1724 1725 fn encode_subscription_mode(mode: RadrootsSimplexSmpSubscriptionMode) -> u8 { 1726 match mode { 1727 RadrootsSimplexSmpSubscriptionMode::Subscribe => b'S', 1728 RadrootsSimplexSmpSubscriptionMode::OnlyCreate => b'C', 1729 } 1730 } 1731 1732 fn decode_subscription_mode( 1733 value: u8, 1734 ) -> Result<RadrootsSimplexSmpSubscriptionMode, RadrootsSimplexSmpProtoError> { 1735 match value { 1736 b'S' => Ok(RadrootsSimplexSmpSubscriptionMode::Subscribe), 1737 b'C' => Ok(RadrootsSimplexSmpSubscriptionMode::OnlyCreate), 1738 _ => Err(RadrootsSimplexSmpProtoError::InvalidTag( 1739 String::from_utf8_lossy(&[value]).into_owned(), 1740 )), 1741 } 1742 } 1743 1744 fn encode_bool(value: bool) -> u8 { 1745 if value { b'T' } else { b'F' } 1746 } 1747 1748 fn decode_bool(value: u8) -> Result<bool, RadrootsSimplexSmpProtoError> { 1749 match value { 1750 b'T' => Ok(true), 1751 b'F' => Ok(false), 1752 other => Err(RadrootsSimplexSmpProtoError::InvalidBoolEncoding(other)), 1753 } 1754 } 1755 1756 fn push_i64(buffer: &mut Vec<u8>, value: i64) { 1757 buffer.extend_from_slice(&value.to_be_bytes()); 1758 } 1759 1760 fn push_short_bytes( 1761 buffer: &mut Vec<u8>, 1762 bytes: &[u8], 1763 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1764 let len = u8::try_from(bytes.len()) 1765 .map_err(|_| RadrootsSimplexSmpProtoError::InvalidShortFieldLength(bytes.len()))?; 1766 buffer.push(len); 1767 buffer.extend_from_slice(bytes); 1768 Ok(()) 1769 } 1770 1771 fn push_short_string( 1772 buffer: &mut Vec<u8>, 1773 value: &str, 1774 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1775 push_short_bytes(buffer, value.as_bytes()) 1776 } 1777 1778 fn push_large_bytes( 1779 buffer: &mut Vec<u8>, 1780 bytes: &[u8], 1781 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1782 let len = u16::try_from(bytes.len()) 1783 .map_err(|_| RadrootsSimplexSmpProtoError::InvalidLargeFieldLength(bytes.len()))?; 1784 buffer.extend_from_slice(&len.to_be_bytes()); 1785 buffer.extend_from_slice(bytes); 1786 Ok(()) 1787 } 1788 1789 fn push_short_key_list( 1790 buffer: &mut Vec<u8>, 1791 keys: &RadrootsSimplexSmpKeyList, 1792 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1793 let len = 1 + keys.rest.len(); 1794 let len = 1795 u8::try_from(len).map_err(|_| RadrootsSimplexSmpProtoError::InvalidListLength(len))?; 1796 buffer.push(len); 1797 push_short_bytes(buffer, &keys.first)?; 1798 for key in &keys.rest { 1799 push_short_bytes(buffer, key)?; 1800 } 1801 Ok(()) 1802 } 1803 1804 fn push_short_string_list( 1805 buffer: &mut Vec<u8>, 1806 values: &[String], 1807 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1808 if values.is_empty() { 1809 return Err(RadrootsSimplexSmpProtoError::InvalidListLength(0)); 1810 } 1811 let len = u8::try_from(values.len()) 1812 .map_err(|_| RadrootsSimplexSmpProtoError::InvalidListLength(values.len()))?; 1813 buffer.push(len); 1814 for value in values { 1815 push_short_string(buffer, value)?; 1816 } 1817 Ok(()) 1818 } 1819 1820 fn push_large_bytes_list( 1821 buffer: &mut Vec<u8>, 1822 values: &[Vec<u8>], 1823 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1824 if values.is_empty() { 1825 return Err(RadrootsSimplexSmpProtoError::InvalidListLength(0)); 1826 } 1827 let len = u8::try_from(values.len()) 1828 .map_err(|_| RadrootsSimplexSmpProtoError::InvalidListLength(values.len()))?; 1829 buffer.push(len); 1830 for value in values { 1831 push_large_bytes(buffer, value)?; 1832 } 1833 Ok(()) 1834 } 1835 1836 fn push_maybe<T, F>( 1837 buffer: &mut Vec<u8>, 1838 value: Option<T>, 1839 mut encode: F, 1840 ) -> Result<(), RadrootsSimplexSmpProtoError> 1841 where 1842 T: Copy, 1843 F: FnMut(&mut Vec<u8>, T) -> Result<(), RadrootsSimplexSmpProtoError>, 1844 { 1845 match value { 1846 None => { 1847 buffer.push(b'0'); 1848 Ok(()) 1849 } 1850 Some(value) => { 1851 buffer.push(b'1'); 1852 encode(buffer, value) 1853 } 1854 } 1855 } 1856 1857 fn push_maybe_short_bytes( 1858 buffer: &mut Vec<u8>, 1859 value: Option<&[u8]>, 1860 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1861 push_maybe(buffer, value, push_short_bytes) 1862 } 1863 1864 fn push_maybe_string( 1865 buffer: &mut Vec<u8>, 1866 value: Option<&str>, 1867 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1868 match value { 1869 None => { 1870 buffer.push(b'0'); 1871 Ok(()) 1872 } 1873 Some(value) => { 1874 validate_basic_auth(value)?; 1875 buffer.push(b'1'); 1876 push_short_bytes(buffer, value.as_bytes()) 1877 } 1878 } 1879 } 1880 1881 fn push_legacy_basic_auth( 1882 buffer: &mut Vec<u8>, 1883 value: Option<&str>, 1884 ) -> Result<(), RadrootsSimplexSmpProtoError> { 1885 match value { 1886 None => Ok(()), 1887 Some(value) => { 1888 validate_basic_auth(value)?; 1889 buffer.push(b'A'); 1890 push_short_bytes(buffer, value.as_bytes()) 1891 } 1892 } 1893 } 1894 1895 fn validate_basic_auth(value: &str) -> Result<(), RadrootsSimplexSmpProtoError> { 1896 if value 1897 .bytes() 1898 .all(|byte| byte.is_ascii_graphic() && byte != b'@' && byte != b':' && byte != b'/') 1899 { 1900 Ok(()) 1901 } else { 1902 Err(RadrootsSimplexSmpProtoError::InvalidUri(value.to_string())) 1903 } 1904 } 1905 1906 struct Cursor<'a> { 1907 bytes: &'a [u8], 1908 offset: usize, 1909 } 1910 1911 impl<'a> Cursor<'a> { 1912 const fn new(bytes: &'a [u8]) -> Self { 1913 Self { bytes, offset: 0 } 1914 } 1915 1916 fn is_empty(&self) -> bool { 1917 self.offset >= self.bytes.len() 1918 } 1919 1920 fn remaining_len(&self) -> usize { 1921 self.bytes.len().saturating_sub(self.offset) 1922 } 1923 1924 fn read_byte(&mut self) -> Result<u8, RadrootsSimplexSmpProtoError> { 1925 let byte = *self 1926 .bytes 1927 .get(self.offset) 1928 .ok_or(RadrootsSimplexSmpProtoError::UnexpectedEof)?; 1929 self.offset += 1; 1930 Ok(byte) 1931 } 1932 1933 fn read_exact(&mut self, len: usize) -> Result<&'a [u8], RadrootsSimplexSmpProtoError> { 1934 let end = self.offset + len; 1935 let value = self 1936 .bytes 1937 .get(self.offset..end) 1938 .ok_or(RadrootsSimplexSmpProtoError::UnexpectedEof)?; 1939 self.offset = end; 1940 Ok(value) 1941 } 1942 1943 fn read_array<const N: usize>(&mut self) -> Result<[u8; N], RadrootsSimplexSmpProtoError> { 1944 let mut array = [0_u8; N]; 1945 array.copy_from_slice(self.read_exact(N)?); 1946 Ok(array) 1947 } 1948 1949 fn read_short_bytes(&mut self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> { 1950 let len = usize::from(self.read_byte()?); 1951 Ok(self.read_exact(len)?.to_vec()) 1952 } 1953 1954 fn read_short_string(&mut self) -> Result<String, RadrootsSimplexSmpProtoError> { 1955 String::from_utf8(self.read_short_bytes()?) 1956 .map_err(|error| RadrootsSimplexSmpProtoError::InvalidUtf8(error.to_string())) 1957 } 1958 1959 fn read_short_string_lossy(&mut self) -> Result<String, RadrootsSimplexSmpProtoError> { 1960 Ok(String::from_utf8_lossy(&self.read_short_bytes()?).into_owned()) 1961 } 1962 1963 fn read_short_key_list( 1964 &mut self, 1965 ) -> Result<RadrootsSimplexSmpKeyList, RadrootsSimplexSmpProtoError> { 1966 let len = usize::from(self.read_byte()?); 1967 if len == 0 { 1968 return Err(RadrootsSimplexSmpProtoError::InvalidListLength(0)); 1969 } 1970 let first = self.read_short_bytes()?; 1971 let mut rest = Vec::with_capacity(len.saturating_sub(1)); 1972 for _ in 1..len { 1973 rest.push(self.read_short_bytes()?); 1974 } 1975 Ok(RadrootsSimplexSmpKeyList { first, rest }) 1976 } 1977 1978 fn read_short_string_list(&mut self) -> Result<Vec<String>, RadrootsSimplexSmpProtoError> { 1979 let len = usize::from(self.read_byte()?); 1980 if len == 0 { 1981 return Err(RadrootsSimplexSmpProtoError::InvalidListLength(0)); 1982 } 1983 let mut values = Vec::with_capacity(len); 1984 for _ in 0..len { 1985 values.push(self.read_short_string()?); 1986 } 1987 Ok(values) 1988 } 1989 1990 fn read_large_bytes(&mut self) -> Result<Vec<u8>, RadrootsSimplexSmpProtoError> { 1991 let len = usize::from(u16::from_be_bytes(self.read_array::<2>()?)); 1992 Ok(self.read_exact(len)?.to_vec()) 1993 } 1994 1995 fn read_large_bytes_list(&mut self) -> Result<Vec<Vec<u8>>, RadrootsSimplexSmpProtoError> { 1996 let len = usize::from(self.read_byte()?); 1997 if len == 0 { 1998 return Err(RadrootsSimplexSmpProtoError::InvalidListLength(0)); 1999 } 2000 let mut values = Vec::with_capacity(len); 2001 for _ in 0..len { 2002 values.push(self.read_large_bytes()?); 2003 } 2004 Ok(values) 2005 } 2006 2007 fn read_i64(&mut self) -> Result<i64, RadrootsSimplexSmpProtoError> { 2008 Ok(i64::from_be_bytes(self.read_array::<8>()?)) 2009 } 2010 2011 fn read_maybe_string(&mut self) -> Result<Option<String>, RadrootsSimplexSmpProtoError> { 2012 self.read_maybe(|cursor| { 2013 let value = cursor.read_short_bytes()?; 2014 let string = String::from_utf8(value) 2015 .map_err(|error| RadrootsSimplexSmpProtoError::InvalidUtf8(error.to_string()))?; 2016 validate_basic_auth(&string)?; 2017 Ok(string) 2018 }) 2019 } 2020 2021 fn read_legacy_basic_auth(&mut self) -> Result<Option<String>, RadrootsSimplexSmpProtoError> { 2022 match self.bytes.get(self.offset).copied() { 2023 Some(b'A') => { 2024 self.offset += 1; 2025 let value = self.read_short_bytes()?; 2026 let string = String::from_utf8(value).map_err(|error| { 2027 RadrootsSimplexSmpProtoError::InvalidUtf8(error.to_string()) 2028 })?; 2029 validate_basic_auth(&string)?; 2030 Ok(Some(string)) 2031 } 2032 Some(_) => Ok(None), 2033 None => Err(RadrootsSimplexSmpProtoError::UnexpectedEof), 2034 } 2035 } 2036 2037 fn read_maybe<T, F>(&mut self, decode: F) -> Result<Option<T>, RadrootsSimplexSmpProtoError> 2038 where 2039 F: FnOnce(&mut Self) -> Result<T, RadrootsSimplexSmpProtoError>, 2040 { 2041 match self.read_byte()? { 2042 b'0' => Ok(None), 2043 b'1' => Ok(Some(decode(self)?)), 2044 other => Err(RadrootsSimplexSmpProtoError::InvalidMaybeTag(other)), 2045 } 2046 } 2047 2048 fn read_remaining(&mut self) -> &'a [u8] { 2049 let remaining = &self.bytes[self.offset..]; 2050 self.offset = self.bytes.len(); 2051 remaining 2052 } 2053 } 2054 2055 #[cfg(test)] 2056 mod tests { 2057 use super::*; 2058 2059 fn correlation_id(byte: u8) -> RadrootsSimplexSmpCorrelationId { 2060 RadrootsSimplexSmpCorrelationId::new([byte; 24]) 2061 } 2062 2063 #[test] 2064 fn round_trips_current_new_command_transmission() { 2065 let transmission = RadrootsSimplexSmpCommandTransmission { 2066 authorization: vec![1, 2, 3], 2067 correlation_id: Some(correlation_id(7)), 2068 entity_id: Vec::new(), 2069 command: RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest { 2070 recipient_auth_public_key: vec![0x01, 0x02, 0x03], 2071 recipient_dh_public_key: vec![0x04, 0x05], 2072 basic_auth: Some("server-pass".to_string()), 2073 subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe, 2074 queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(Some( 2075 RadrootsSimplexSmpMessagingQueueRequest { 2076 sender_id: vec![0x10, 0x11], 2077 link_data: RadrootsSimplexSmpQueueLinkData { 2078 fixed_data: vec![0xaa, 0xbb], 2079 user_data: vec![0xcc, 0xdd, 0xee], 2080 }, 2081 }, 2082 ))), 2083 notifier_credentials: Some(RadrootsSimplexSmpNewNotifierCredentials { 2084 notifier_auth_public_key: vec![0x21, 0x22], 2085 recipient_notification_dh_public_key: vec![0x23, 0x24], 2086 }), 2087 }), 2088 }; 2089 2090 let encoded = transmission.encode().unwrap(); 2091 let decoded = RadrootsSimplexSmpCommandTransmission::decode(&encoded).unwrap(); 2092 assert_eq!(decoded, transmission); 2093 } 2094 2095 #[test] 2096 fn round_trips_v9_new_command_transmission() { 2097 let transmission = RadrootsSimplexSmpCommandTransmission { 2098 authorization: vec![1, 2, 3], 2099 correlation_id: Some(correlation_id(7)), 2100 entity_id: Vec::new(), 2101 command: RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest { 2102 recipient_auth_public_key: vec![0x01, 0x02, 0x03], 2103 recipient_dh_public_key: vec![0x04, 0x05], 2104 basic_auth: Some("server-pass".to_string()), 2105 subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe, 2106 queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(None)), 2107 notifier_credentials: None, 2108 }), 2109 }; 2110 2111 let encoded = transmission 2112 .encode_for_version(RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION) 2113 .unwrap(); 2114 let decoded = RadrootsSimplexSmpCommandTransmission::decode_for_version( 2115 RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION, 2116 &encoded, 2117 ) 2118 .unwrap(); 2119 assert_eq!(decoded, transmission); 2120 } 2121 2122 #[test] 2123 fn round_trips_v6_new_command_transmission() { 2124 let transmission = RadrootsSimplexSmpCommandTransmission { 2125 authorization: vec![1, 2, 3], 2126 correlation_id: Some(correlation_id(7)), 2127 entity_id: Vec::new(), 2128 command: RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest { 2129 recipient_auth_public_key: vec![0x01, 0x02, 0x03], 2130 recipient_dh_public_key: vec![0x04, 0x05], 2131 basic_auth: Some("server-pass".to_string()), 2132 subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe, 2133 queue_request_data: None, 2134 notifier_credentials: None, 2135 }), 2136 }; 2137 2138 let encoded = transmission 2139 .encode_for_version(RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION) 2140 .unwrap(); 2141 let decoded = RadrootsSimplexSmpCommandTransmission::decode_for_version( 2142 RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION, 2143 &encoded, 2144 ) 2145 .unwrap(); 2146 assert_eq!(decoded, transmission); 2147 } 2148 2149 #[test] 2150 fn round_trips_send_command_transmission() { 2151 let transmission = RadrootsSimplexSmpCommandTransmission { 2152 authorization: Vec::new(), 2153 correlation_id: Some(correlation_id(9)), 2154 entity_id: vec![0xaa, 0xbb], 2155 command: RadrootsSimplexSmpCommand::Send(RadrootsSimplexSmpSendCommand { 2156 flags: RadrootsSimplexSmpMessageFlags { 2157 notification: true, 2158 reserved: b"0".to_vec(), 2159 }, 2160 message_body: vec![0xde, 0xad, 0xbe, 0xef], 2161 }), 2162 }; 2163 2164 let encoded = transmission.encode().unwrap(); 2165 let decoded = RadrootsSimplexSmpCommandTransmission::decode(&encoded).unwrap(); 2166 assert_eq!(decoded, transmission); 2167 } 2168 2169 #[test] 2170 fn round_trips_v15_new_command_transmission() { 2171 let transmission = RadrootsSimplexSmpCommandTransmission { 2172 authorization: vec![1, 2, 3], 2173 correlation_id: Some(correlation_id(7)), 2174 entity_id: Vec::new(), 2175 command: RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest { 2176 recipient_auth_public_key: vec![0x01, 0x02, 0x03], 2177 recipient_dh_public_key: vec![0x04, 0x05], 2178 basic_auth: Some("server-pass".to_string()), 2179 subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe, 2180 queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(Some( 2181 RadrootsSimplexSmpMessagingQueueRequest { 2182 sender_id: vec![0x10, 0x11], 2183 link_data: RadrootsSimplexSmpQueueLinkData { 2184 fixed_data: vec![0xaa, 0xbb], 2185 user_data: vec![0xcc, 0xdd, 0xee], 2186 }, 2187 }, 2188 ))), 2189 notifier_credentials: None, 2190 }), 2191 }; 2192 2193 let encoded = transmission 2194 .encode_for_version(RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION) 2195 .unwrap(); 2196 let decoded = RadrootsSimplexSmpCommandTransmission::decode_for_version( 2197 RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION, 2198 &encoded, 2199 ) 2200 .unwrap(); 2201 assert_eq!(decoded, transmission); 2202 } 2203 2204 #[test] 2205 fn current_authenticated_transmission_encodes_absent_service_signature_as_maybe_none() { 2206 let transmission = RadrootsSimplexSmpCommandTransmission { 2207 authorization: vec![1, 2, 3], 2208 correlation_id: Some(correlation_id(7)), 2209 entity_id: Vec::new(), 2210 command: RadrootsSimplexSmpCommand::Ping, 2211 }; 2212 2213 let encoded = transmission.encode().unwrap(); 2214 assert_eq!(encoded[0], 3); 2215 assert_eq!(&encoded[1..4], &[1, 2, 3]); 2216 assert_eq!(encoded[4], b'0'); 2217 2218 let decoded = RadrootsSimplexSmpCommandTransmission::decode(&encoded).unwrap(); 2219 assert_eq!(decoded, transmission); 2220 } 2221 2222 #[test] 2223 fn round_trips_current_ids_broker_transmission() { 2224 let transmission = RadrootsSimplexSmpBrokerTransmission { 2225 authorization: Vec::new(), 2226 correlation_id: Some(correlation_id(3)), 2227 entity_id: Vec::new(), 2228 message: RadrootsSimplexSmpBrokerMessage::Ids(RadrootsSimplexSmpQueueIdsResponse { 2229 recipient_id: vec![0x10], 2230 sender_id: vec![0x11], 2231 server_dh_public_key: vec![0x12, 0x13], 2232 queue_mode: Some(RadrootsSimplexSmpQueueMode::Messaging), 2233 link_id: Some(vec![0x14, 0x15]), 2234 service_id: Some(vec![0x16, 0x17]), 2235 server_notification_credentials: Some( 2236 RadrootsSimplexSmpServerNotifierCredentials { 2237 notifier_id: vec![0x18, 0x19], 2238 server_notification_dh_public_key: vec![0x1a, 0x1b], 2239 }, 2240 ), 2241 }), 2242 }; 2243 2244 let encoded = transmission.encode().unwrap(); 2245 let decoded = RadrootsSimplexSmpBrokerTransmission::decode(&encoded).unwrap(); 2246 assert_eq!(decoded, transmission); 2247 } 2248 2249 #[test] 2250 fn round_trips_v9_ids_broker_transmission() { 2251 let transmission = RadrootsSimplexSmpBrokerTransmission { 2252 authorization: Vec::new(), 2253 correlation_id: Some(correlation_id(3)), 2254 entity_id: Vec::new(), 2255 message: RadrootsSimplexSmpBrokerMessage::Ids(RadrootsSimplexSmpQueueIdsResponse { 2256 recipient_id: vec![0x10], 2257 sender_id: vec![0x11], 2258 server_dh_public_key: vec![0x12, 0x13], 2259 queue_mode: Some(RadrootsSimplexSmpQueueMode::Messaging), 2260 link_id: None, 2261 service_id: None, 2262 server_notification_credentials: None, 2263 }), 2264 }; 2265 2266 let encoded = transmission 2267 .encode_for_version(RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION) 2268 .unwrap(); 2269 let decoded = RadrootsSimplexSmpBrokerTransmission::decode_for_version( 2270 RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION, 2271 &encoded, 2272 ) 2273 .unwrap(); 2274 assert_eq!(decoded, transmission); 2275 } 2276 2277 #[test] 2278 fn round_trips_error_broker_transmission() { 2279 let transmission = RadrootsSimplexSmpBrokerTransmission { 2280 authorization: Vec::new(), 2281 correlation_id: Some(correlation_id(5)), 2282 entity_id: vec![0x01], 2283 message: RadrootsSimplexSmpBrokerMessage::Err(RadrootsSimplexSmpError::Command( 2284 RadrootsSimplexSmpCommandError::Prohibited, 2285 )), 2286 }; 2287 2288 let encoded = transmission.encode().unwrap(); 2289 let decoded = RadrootsSimplexSmpBrokerTransmission::decode(&encoded).unwrap(); 2290 assert_eq!(decoded, transmission); 2291 } 2292 2293 #[test] 2294 fn round_trips_message_notification() { 2295 let transmission = RadrootsSimplexSmpBrokerTransmission { 2296 authorization: Vec::new(), 2297 correlation_id: None, 2298 entity_id: vec![0x99], 2299 message: RadrootsSimplexSmpBrokerMessage::NMsg { 2300 nonce: [0x22; 24], 2301 encrypted_metadata: vec![0x33, 0x44, 0x55], 2302 }, 2303 }; 2304 2305 let encoded = transmission.encode().unwrap(); 2306 let decoded = RadrootsSimplexSmpBrokerTransmission::decode(&encoded).unwrap(); 2307 assert_eq!(decoded, transmission); 2308 } 2309 2310 #[test] 2311 fn v6_new_command_uses_legacy_basic_auth_layout() { 2312 let command = RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest { 2313 recipient_auth_public_key: vec![0x01, 0x02, 0x03], 2314 recipient_dh_public_key: vec![0x04, 0x05], 2315 basic_auth: Some("server-pass".to_string()), 2316 subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe, 2317 queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(None)), 2318 notifier_credentials: Some(RadrootsSimplexSmpNewNotifierCredentials { 2319 notifier_auth_public_key: vec![0x21, 0x22], 2320 recipient_notification_dh_public_key: vec![0x23, 0x24], 2321 }), 2322 }); 2323 2324 let encoded = command 2325 .encode_for_version(RADROOTS_SIMPLEX_SMP_INITIAL_TRANSPORT_VERSION) 2326 .unwrap(); 2327 2328 assert_eq!( 2329 encoded, 2330 b"NEW \x03\x01\x02\x03\x02\x04\x05A\x0bserver-passS".to_vec() 2331 ); 2332 } 2333 2334 #[test] 2335 fn v9_new_matches_official_sender_secure_layout() { 2336 let command = RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest { 2337 recipient_auth_public_key: vec![0x01, 0x02, 0x03], 2338 recipient_dh_public_key: vec![0x04, 0x05], 2339 basic_auth: Some("server-pass".to_string()), 2340 subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe, 2341 queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(None)), 2342 notifier_credentials: None, 2343 }); 2344 2345 let encoded = command 2346 .encode_for_version(RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION) 2347 .unwrap(); 2348 2349 assert_eq!( 2350 encoded, 2351 b"NEW \x03\x01\x02\x03\x02\x04\x051\x0bserver-passST".to_vec() 2352 ); 2353 } 2354 2355 #[test] 2356 fn v15_new_matches_official_short_link_layout() { 2357 let command = RadrootsSimplexSmpCommand::New(RadrootsSimplexSmpNewQueueRequest { 2358 recipient_auth_public_key: vec![0x01, 0x02, 0x03], 2359 recipient_dh_public_key: vec![0x04, 0x05], 2360 basic_auth: Some("server-pass".to_string()), 2361 subscription_mode: RadrootsSimplexSmpSubscriptionMode::Subscribe, 2362 queue_request_data: Some(RadrootsSimplexSmpQueueRequestData::Messaging(Some( 2363 RadrootsSimplexSmpMessagingQueueRequest { 2364 sender_id: vec![0x10, 0x11], 2365 link_data: RadrootsSimplexSmpQueueLinkData { 2366 fixed_data: vec![0xaa, 0xbb], 2367 user_data: vec![0xcc, 0xdd, 0xee], 2368 }, 2369 }, 2370 ))), 2371 notifier_credentials: Some(RadrootsSimplexSmpNewNotifierCredentials { 2372 notifier_auth_public_key: vec![0x21, 0x22], 2373 recipient_notification_dh_public_key: vec![0x23, 0x24], 2374 }), 2375 }); 2376 2377 let encoded = command 2378 .encode_for_version(RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION) 2379 .unwrap(); 2380 2381 assert_eq!( 2382 encoded, 2383 b"NEW \x03\x01\x02\x03\x02\x04\x051\x0bserver-passS1M1\x02\x10\x11\x00\x02\xaa\xbb\x00\x03\xcc\xdd\xee" 2384 .to_vec() 2385 ); 2386 } 2387 2388 #[test] 2389 fn v17_ids_matches_official_notifier_layout() { 2390 let response = RadrootsSimplexSmpBrokerMessage::Ids(RadrootsSimplexSmpQueueIdsResponse { 2391 recipient_id: vec![0x10], 2392 sender_id: vec![0x11], 2393 server_dh_public_key: vec![0x12, 0x13], 2394 queue_mode: Some(RadrootsSimplexSmpQueueMode::Messaging), 2395 link_id: Some(vec![0x14, 0x15]), 2396 service_id: Some(vec![0x16, 0x17]), 2397 server_notification_credentials: Some(RadrootsSimplexSmpServerNotifierCredentials { 2398 notifier_id: vec![0x18, 0x19], 2399 server_notification_dh_public_key: vec![0x1a, 0x1b], 2400 }), 2401 }); 2402 2403 let encoded = response.encode().unwrap(); 2404 2405 assert_eq!( 2406 encoded, 2407 b"IDS \x01\x10\x01\x11\x02\x12\x131M1\x02\x14\x151\x02\x16\x171\x02\x18\x19\x02\x1a\x1b" 2408 .to_vec() 2409 ); 2410 } 2411 2412 #[test] 2413 fn v15_ids_matches_official_short_link_layout() { 2414 let response = RadrootsSimplexSmpBrokerMessage::Ids(RadrootsSimplexSmpQueueIdsResponse { 2415 recipient_id: vec![0x10], 2416 sender_id: vec![0x11], 2417 server_dh_public_key: vec![0x12, 0x13], 2418 queue_mode: Some(RadrootsSimplexSmpQueueMode::Messaging), 2419 link_id: Some(vec![0x14, 0x15]), 2420 service_id: Some(vec![0x16, 0x17]), 2421 server_notification_credentials: None, 2422 }); 2423 2424 let encoded = response 2425 .encode_for_version(RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION) 2426 .unwrap(); 2427 2428 assert_eq!( 2429 encoded, 2430 b"IDS \x01\x10\x01\x11\x02\x12\x131M1\x02\x14\x15".to_vec() 2431 ); 2432 } 2433 2434 #[test] 2435 fn v9_ids_matches_official_sender_secure_layout() { 2436 let response = RadrootsSimplexSmpBrokerMessage::Ids(RadrootsSimplexSmpQueueIdsResponse { 2437 recipient_id: vec![0x10], 2438 sender_id: vec![0x11], 2439 server_dh_public_key: vec![0x12, 0x13], 2440 queue_mode: Some(RadrootsSimplexSmpQueueMode::Messaging), 2441 link_id: Some(vec![0x14, 0x15]), 2442 service_id: Some(vec![0x16, 0x17]), 2443 server_notification_credentials: None, 2444 }); 2445 2446 let encoded = response 2447 .encode_for_version(RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION) 2448 .unwrap(); 2449 2450 assert_eq!(encoded, b"IDS \x01\x10\x01\x11\x02\x12\x13T".to_vec()); 2451 } 2452 2453 #[test] 2454 fn prxy_matches_official_proxy_session_layout() { 2455 let command = RadrootsSimplexSmpCommand::Prxy { 2456 server: RadrootsSimplexSmpProtocolServer { 2457 hosts: vec![ 2458 "smp4.simplex.im".to_string(), 2459 "simplexabc.onion".to_string(), 2460 ], 2461 port: "5223".to_string(), 2462 key_hash: vec![0xaa, 0xbb, 0xcc], 2463 }, 2464 basic_auth: Some("relay-pass".to_string()), 2465 }; 2466 2467 let encoded = command.encode().unwrap(); 2468 2469 assert_eq!( 2470 encoded, 2471 b"PRXY \x02\x0fsmp4.simplex.im\x10simplexabc.onion\x045223\x03\xaa\xbb\xcc1\x0arelay-pass" 2472 .to_vec() 2473 ); 2474 } 2475 2476 #[test] 2477 fn pkey_matches_official_proxy_session_key_layout() { 2478 let message = RadrootsSimplexSmpBrokerMessage::PKey { 2479 session_id: vec![0x31, 0x32], 2480 version_range: RadrootsSimplexSmpVersionRange::new(8, 16).unwrap(), 2481 cert_chain_public_key: RadrootsSimplexSmpCertChainPublicKey { 2482 certificate_chain: vec![vec![0x41, 0x42], vec![0x43, 0x44, 0x45]], 2483 signed_public_key: vec![0x51, 0x52, 0x53], 2484 }, 2485 }; 2486 2487 let encoded = message.encode().unwrap(); 2488 2489 assert_eq!( 2490 encoded, 2491 b"PKEY \x0212\x00\x08\x00\x10\x02\x00\x02AB\x00\x03CDE\x00\x03QRS".to_vec() 2492 ); 2493 } 2494 2495 #[test] 2496 fn proxy_transport_error_matches_official_nested_error_layout() { 2497 let encoded = RadrootsSimplexSmpBrokerMessage::Err(RadrootsSimplexSmpError::Proxy( 2498 RadrootsSimplexSmpProxyError::Broker(RadrootsSimplexSmpBrokerError::Transport( 2499 RadrootsSimplexSmpTransportError::Handshake( 2500 RadrootsSimplexSmpHandshakeError::Identity, 2501 ), 2502 )), 2503 )) 2504 .encode() 2505 .unwrap(); 2506 2507 assert_eq!( 2508 encoded, 2509 b"ERR PROXY BROKER TRANSPORT HANDSHAKE IDENTITY".to_vec() 2510 ); 2511 } 2512 2513 #[test] 2514 fn round_trips_proxy_and_short_link_commands() { 2515 let prxy = RadrootsSimplexSmpCommandTransmission { 2516 authorization: Vec::new(), 2517 correlation_id: Some(correlation_id(1)), 2518 entity_id: Vec::new(), 2519 command: RadrootsSimplexSmpCommand::Prxy { 2520 server: RadrootsSimplexSmpProtocolServer { 2521 hosts: vec![ 2522 "smp4.simplex.im".to_string(), 2523 "simplexabc.onion".to_string(), 2524 ], 2525 port: "5223".to_string(), 2526 key_hash: vec![0xaa, 0xbb, 0xcc], 2527 }, 2528 basic_auth: Some("relay-pass".to_string()), 2529 }, 2530 }; 2531 2532 let rkey = RadrootsSimplexSmpCommandTransmission { 2533 authorization: vec![0x42], 2534 correlation_id: Some(correlation_id(2)), 2535 entity_id: vec![0x11], 2536 command: RadrootsSimplexSmpCommand::RKey(RadrootsSimplexSmpKeyList { 2537 first: vec![0x01, 0x02], 2538 rest: vec![vec![0x03, 0x04], vec![0x05, 0x06]], 2539 }), 2540 }; 2541 2542 let pkey_encoded = prxy.encode().unwrap(); 2543 let pkey_decoded = RadrootsSimplexSmpCommandTransmission::decode(&pkey_encoded).unwrap(); 2544 assert_eq!(pkey_decoded, prxy); 2545 2546 let rkey_encoded = rkey.encode().unwrap(); 2547 let rkey_decoded = RadrootsSimplexSmpCommandTransmission::decode(&rkey_encoded).unwrap(); 2548 assert_eq!(rkey_decoded, rkey); 2549 } 2550 2551 #[test] 2552 fn protocol_server_accepts_official_transport_host_forms() { 2553 let server = RadrootsSimplexSmpProtocolServer { 2554 hosts: vec![ 2555 "smp4.simplex.im".to_string(), 2556 "192.0.2.24".to_string(), 2557 "2001:db8::24".to_string(), 2558 "[2001:db8::42]".to_string(), 2559 "simplexabc.onion".to_string(), 2560 ], 2561 port: "5223".to_string(), 2562 key_hash: vec![0xaa, 0xbb, 0xcc], 2563 }; 2564 2565 let mut encoded = Vec::new(); 2566 encode_protocol_server(&mut encoded, &server).unwrap(); 2567 let decoded = decode_protocol_server(&mut Cursor::new(&encoded)).unwrap(); 2568 2569 assert_eq!(decoded, server); 2570 } 2571 2572 #[test] 2573 fn protocol_server_rejects_invalid_transport_host_forms() { 2574 let invalid_server = RadrootsSimplexSmpProtocolServer { 2575 hosts: vec!["bad host".to_string()], 2576 port: "5223".to_string(), 2577 key_hash: vec![0xaa, 0xbb, 0xcc], 2578 }; 2579 2580 let mut encoded = Vec::new(); 2581 assert_eq!( 2582 encode_protocol_server(&mut encoded, &invalid_server), 2583 Err(RadrootsSimplexSmpProtoError::InvalidHostList( 2584 "bad host".to_string(), 2585 )) 2586 ); 2587 2588 let mut invalid_bytes = Vec::new(); 2589 push_short_string_list(&mut invalid_bytes, &["[invalid]".to_string()]).unwrap(); 2590 push_short_string(&mut invalid_bytes, "5223").unwrap(); 2591 push_short_bytes(&mut invalid_bytes, &[0xaa, 0xbb, 0xcc]).unwrap(); 2592 2593 assert_eq!( 2594 decode_protocol_server(&mut Cursor::new(&invalid_bytes)), 2595 Err(RadrootsSimplexSmpProtoError::InvalidHostList( 2596 "[invalid]".to_string(), 2597 )) 2598 ); 2599 } 2600 2601 #[test] 2602 fn top_level_unknown_error_tags_stay_opaque() { 2603 assert_eq!( 2604 decode_error(b"FUTURE"), 2605 Ok(RadrootsSimplexSmpError::Other(b"FUTURE".to_vec())) 2606 ); 2607 } 2608 2609 #[test] 2610 fn malformed_nested_proxy_error_fails_decode() { 2611 assert_eq!( 2612 decode_error(b"PROXY BROKER TRANSPORT HANDSHAKE UNKNOWN"), 2613 Err(RadrootsSimplexSmpProtoError::InvalidTag( 2614 "UNKNOWN".to_string(), 2615 )) 2616 ); 2617 } 2618 2619 #[test] 2620 fn malformed_blocked_reason_fails_decode() { 2621 assert_eq!( 2622 decode_error(b"BLOCKED reason=custom"), 2623 Err(RadrootsSimplexSmpProtoError::InvalidTag( 2624 "custom".to_string(), 2625 )) 2626 ); 2627 } 2628 2629 #[test] 2630 fn malformed_network_detail_fails_decode() { 2631 assert_eq!( 2632 decode_broker_error(b"NETWORK CONNECT"), 2633 Err(RadrootsSimplexSmpProtoError::UnexpectedEof) 2634 ); 2635 } 2636 2637 #[test] 2638 fn round_trips_proxy_forward_commands() { 2639 let pfwd = RadrootsSimplexSmpCommandTransmission { 2640 authorization: Vec::new(), 2641 correlation_id: Some(correlation_id(3)), 2642 entity_id: vec![0x90, 0x91], 2643 command: RadrootsSimplexSmpCommand::PFwd { 2644 relay_version: 16, 2645 public_key: vec![0x10, 0x11, 0x12], 2646 encrypted_transmission: vec![0xde, 0xad, 0xbe, 0xef], 2647 }, 2648 }; 2649 let rfwd = RadrootsSimplexSmpCommandTransmission { 2650 authorization: Vec::new(), 2651 correlation_id: Some(correlation_id(4)), 2652 entity_id: Vec::new(), 2653 command: RadrootsSimplexSmpCommand::RFwd(vec![0xca, 0xfe, 0xba, 0xbe]), 2654 }; 2655 2656 let pfwd_encoded = pfwd.encode().unwrap(); 2657 let pfwd_decoded = RadrootsSimplexSmpCommandTransmission::decode(&pfwd_encoded).unwrap(); 2658 assert_eq!(pfwd_decoded, pfwd); 2659 2660 let rfwd_encoded = rfwd.encode().unwrap(); 2661 let rfwd_decoded = RadrootsSimplexSmpCommandTransmission::decode(&rfwd_encoded).unwrap(); 2662 assert_eq!(rfwd_decoded, rfwd); 2663 } 2664 2665 #[test] 2666 fn round_trips_service_and_proxy_broker_messages() { 2667 let service = RadrootsSimplexSmpBrokerTransmission { 2668 authorization: Vec::new(), 2669 correlation_id: Some(correlation_id(5)), 2670 entity_id: vec![0x44], 2671 message: RadrootsSimplexSmpBrokerMessage::Sok(Some(vec![0x20, 0x21])), 2672 }; 2673 let proxy = RadrootsSimplexSmpBrokerTransmission { 2674 authorization: Vec::new(), 2675 correlation_id: None, 2676 entity_id: Vec::new(), 2677 message: RadrootsSimplexSmpBrokerMessage::PKey { 2678 session_id: vec![0x31, 0x32], 2679 version_range: RadrootsSimplexSmpVersionRange::new(8, 16).unwrap(), 2680 cert_chain_public_key: RadrootsSimplexSmpCertChainPublicKey { 2681 certificate_chain: vec![vec![0x41, 0x42], vec![0x43, 0x44, 0x45]], 2682 signed_public_key: vec![0x51, 0x52, 0x53], 2683 }, 2684 }, 2685 }; 2686 2687 let service_encoded = service.encode().unwrap(); 2688 let service_decoded = 2689 RadrootsSimplexSmpBrokerTransmission::decode(&service_encoded).unwrap(); 2690 assert_eq!(service_decoded, service); 2691 2692 let proxy_encoded = proxy.encode().unwrap(); 2693 let proxy_decoded = RadrootsSimplexSmpBrokerTransmission::decode(&proxy_encoded).unwrap(); 2694 assert_eq!(proxy_decoded, proxy); 2695 } 2696 2697 #[test] 2698 fn round_trips_proxy_and_blocked_errors() { 2699 let proxy_error = RadrootsSimplexSmpBrokerTransmission { 2700 authorization: Vec::new(), 2701 correlation_id: Some(correlation_id(6)), 2702 entity_id: vec![0x77], 2703 message: RadrootsSimplexSmpBrokerMessage::Err(RadrootsSimplexSmpError::Proxy( 2704 RadrootsSimplexSmpProxyError::Broker(RadrootsSimplexSmpBrokerError::Transport( 2705 RadrootsSimplexSmpTransportError::Handshake( 2706 RadrootsSimplexSmpHandshakeError::Identity, 2707 ), 2708 )), 2709 )), 2710 }; 2711 let blocked_error = RadrootsSimplexSmpBrokerTransmission { 2712 authorization: Vec::new(), 2713 correlation_id: Some(correlation_id(7)), 2714 entity_id: vec![0x88], 2715 message: RadrootsSimplexSmpBrokerMessage::Err(RadrootsSimplexSmpError::Blocked( 2716 RadrootsSimplexSmpBlockingInfo { 2717 reason: RadrootsSimplexSmpBlockingReason::Spam, 2718 }, 2719 )), 2720 }; 2721 2722 let proxy_encoded = proxy_error.encode().unwrap(); 2723 let proxy_decoded = RadrootsSimplexSmpBrokerTransmission::decode(&proxy_encoded).unwrap(); 2724 assert_eq!(proxy_decoded, proxy_error); 2725 2726 let blocked_encoded = blocked_error.encode().unwrap(); 2727 let blocked_decoded = 2728 RadrootsSimplexSmpBrokerTransmission::decode(&blocked_encoded).unwrap(); 2729 assert_eq!(blocked_decoded, blocked_error); 2730 } 2731 2732 #[test] 2733 fn service_ok_downgrades_to_ok_before_service_certs() { 2734 let encoded = RadrootsSimplexSmpBrokerMessage::Sok(Some(vec![0x10])) 2735 .encode_for_version(RADROOTS_SIMPLEX_SMP_SHORT_LINKS_TRANSPORT_VERSION) 2736 .unwrap(); 2737 2738 assert_eq!(encoded, b"OK".to_vec()); 2739 } 2740 2741 #[test] 2742 fn blocked_error_downgrades_to_auth_before_blocked_entity_version() { 2743 let encoded = RadrootsSimplexSmpBrokerMessage::Err(RadrootsSimplexSmpError::Blocked( 2744 RadrootsSimplexSmpBlockingInfo { 2745 reason: RadrootsSimplexSmpBlockingReason::Content, 2746 }, 2747 )) 2748 .encode_for_version(RADROOTS_SIMPLEX_SMP_SENDER_AUTH_KEY_TRANSPORT_VERSION) 2749 .unwrap(); 2750 2751 assert_eq!(encoded, b"ERR AUTH".to_vec()); 2752 } 2753 2754 #[test] 2755 fn decodes_optional_network_detail_and_preserves_encode_behavior() { 2756 let detailed = decode_broker_error(b"NETWORK CONNECT \x03dns").unwrap(); 2757 assert_eq!( 2758 detailed, 2759 RadrootsSimplexSmpBrokerError::Network(RadrootsSimplexSmpNetworkError::Connect( 2760 "dns".to_string(), 2761 )) 2762 ); 2763 2764 let encoded = 2765 encode_network_error(&RadrootsSimplexSmpNetworkError::Connect("dns".to_string())); 2766 assert_eq!(encoded, b"CONNECT \x03dns".to_vec()); 2767 assert_eq!( 2768 encode_broker_error(&RadrootsSimplexSmpBrokerError::Network( 2769 RadrootsSimplexSmpNetworkError::Connect("dns".to_string()), 2770 )), 2771 b"NETWORK".to_vec() 2772 ); 2773 } 2774 }