1use std::{collections::HashSet, time::SystemTime};
2
3use chrono::prelude::*;
4use libsignal_core::{curve::CurveError, InvalidDeviceId};
5use libsignal_protocol::{
6 process_prekey_bundle, Aci, DeviceId, IdentityKey, IdentityKeyPair, Pni,
7 ProtocolStore, SenderCertificate, SenderKeyStore, ServiceId,
8 SessionNotFound, SignalProtocolError,
9};
10use rand::{rng, CryptoRng, Rng};
11use tracing::{debug, error, info, trace, warn};
12use tracing_futures::Instrument;
13use uuid::Uuid;
14use zkgroup::GROUP_IDENTIFIER_LEN;
15
16use crate::{
17 cipher::{get_preferred_protocol_address, ServiceCipher},
18 content::ContentBody,
19 proto::{
20 attachment_pointer::{
21 AttachmentIdentifier, Flags as AttachmentPointerFlags,
22 },
23 sync_message::{
24 self, message_request_response, MessageRequestResponse,
25 },
26 AttachmentPointer, SyncMessage,
27 },
28 push_service::*,
29 service_address::ServiceIdExt,
30 session_store::SessionStoreExt,
31 unidentified_access::UnidentifiedAccess,
32 utils::{serde_device_id, serde_service_id},
33 websocket::{self, SignalWebSocket},
34};
35
36pub use crate::proto::ContactDetails;
37
38#[derive(serde::Serialize, Debug)]
39#[serde(rename_all = "camelCase")]
40pub struct OutgoingPushMessage {
41 pub r#type: u32,
42 #[serde(with = "serde_device_id")]
43 pub destination_device_id: DeviceId,
44 pub destination_registration_id: u32,
45 pub content: String,
46}
47
48#[derive(serde::Serialize, Debug)]
49pub struct OutgoingPushMessages {
50 #[serde(with = "serde_service_id")]
51 pub destination: ServiceId,
52 pub timestamp: u64,
53 pub messages: Vec<OutgoingPushMessage>,
54 pub online: bool,
55}
56
57#[derive(serde::Deserialize, Debug)]
58#[serde(rename_all = "camelCase")]
59pub struct SendMessageResponse {
60 pub needs_sync: bool,
61}
62
63pub type SendMessageResult = Result<SentMessage, MessageSenderError>;
64
65#[derive(Debug, Clone)]
66pub struct SentMessage {
67 pub recipient: ServiceId,
68 pub used_identity_key: IdentityKey,
69 pub unidentified: bool,
70 pub needs_sync: bool,
71}
72
73#[derive(Debug, Default)]
77pub struct AttachmentSpec {
78 pub content_type: String,
79 pub length: usize,
80 pub file_name: Option<String>,
81 pub preview: Option<Vec<u8>>,
82 pub voice_note: Option<bool>,
83 pub borderless: Option<bool>,
84 pub width: Option<u32>,
85 pub height: Option<u32>,
86 pub caption: Option<String>,
87 pub blur_hash: Option<String>,
88}
89
90#[derive(Clone)]
91pub struct MessageSender<S> {
92 identified_ws: SignalWebSocket<websocket::Identified>,
93 unidentified_ws: SignalWebSocket<websocket::Unidentified>,
94 service: PushService,
95 cipher: ServiceCipher<S>,
96 protocol_store: S,
97 local_aci: Aci,
98 local_pni: Pni,
99 aci_identity: IdentityKeyPair,
100 pni_identity: Option<IdentityKeyPair>,
101 device_id: DeviceId,
102}
103
104#[derive(thiserror::Error, Debug)]
105pub enum AttachmentUploadError {
106 #[error("{0}")]
107 ServiceError(#[from] ServiceError),
108
109 #[error("Could not read attachment contents")]
110 IoError(#[from] std::io::Error),
111}
112
113#[derive(thiserror::Error, Debug)]
114pub enum MessageSenderError {
115 #[error("service error: {0}")]
116 ServiceError(#[from] ServiceError),
117
118 #[error("protocol error: {0}")]
119 ProtocolError(#[from] SignalProtocolError),
120
121 #[error("invalid private key: {0}")]
122 InvalidPrivateKey(#[from] CurveError),
123
124 #[error("invalid device ID: {0}")]
125 InvalidDeviceId(#[from] InvalidDeviceId),
126
127 #[error("Failed to upload attachment {0}")]
128 AttachmentUploadError(#[from] AttachmentUploadError),
129
130 #[error("primary device can't send sync message {0:?}")]
131 SendSyncMessageError(sync_message::request::Type),
132
133 #[error("Untrusted identity key with {address:?}")]
134 UntrustedIdentity { address: ServiceId },
135
136 #[error("Exceeded maximum number of retries")]
137 MaximumRetriesLimitExceeded,
138
139 #[error("Proof of type {options:?} required using token {token}")]
140 ProofRequired { token: String, options: Vec<String> },
141
142 #[error("Recipient not found: {service_id:?}")]
143 NotFound { service_id: ServiceId },
144
145 #[error("no messages were encrypted: this should not really happen and most likely implies a logic error")]
146 NoMessagesToSend,
147}
148
149pub type GroupV2Id = [u8; GROUP_IDENTIFIER_LEN];
150
151#[derive(Debug)]
152pub enum ThreadIdentifier {
153 Aci(Uuid),
154 Group(GroupV2Id),
155}
156
157#[derive(Debug)]
158pub struct EncryptedMessages {
159 messages: Vec<OutgoingPushMessage>,
160 used_identity_key: IdentityKey,
161}
162
163impl<S> MessageSender<S>
164where
165 S: ProtocolStore + SenderKeyStore + SessionStoreExt + Sync + Clone,
166{
167 #[allow(clippy::too_many_arguments)]
168 pub fn new(
169 identified_ws: SignalWebSocket<websocket::Identified>,
170 unidentified_ws: SignalWebSocket<websocket::Unidentified>,
171 service: PushService,
172 cipher: ServiceCipher<S>,
173 protocol_store: S,
174 local_aci: impl Into<Aci>,
175 local_pni: impl Into<Pni>,
176 aci_identity: IdentityKeyPair,
177 pni_identity: Option<IdentityKeyPair>,
178 device_id: DeviceId,
179 ) -> Self {
180 MessageSender {
181 service,
182 identified_ws,
183 unidentified_ws,
184 cipher,
185 protocol_store,
186 local_aci: local_aci.into(),
187 local_pni: local_pni.into(),
188 aci_identity,
189 pni_identity,
190 device_id,
191 }
192 }
193
194 #[tracing::instrument(skip(self, contents, csprng), fields(size = contents.len()))]
198 pub async fn upload_attachment<R: Rng + CryptoRng>(
199 &mut self,
200 spec: AttachmentSpec,
201 mut contents: Vec<u8>,
202 csprng: &mut R,
203 ) -> Result<AttachmentPointer, AttachmentUploadError> {
204 let len = contents.len();
205 let (key, iv) = {
207 let mut key = [0u8; 64];
208 let mut iv = [0u8; 16];
209 csprng.fill_bytes(&mut key);
210 csprng.fill_bytes(&mut iv);
211 (key, iv)
212 };
213
214 let padded_len: usize = {
218 std::cmp::max(
221 541,
222 1.05f64.powf((len as f64).log(1.05).ceil()).floor() as usize,
223 )
224 };
225 if padded_len < len {
226 error!(
227 "Padded len {} < len {}. Continuing with a privacy risk.",
228 padded_len, len
229 );
230 } else {
231 contents.resize(padded_len, 0);
232 }
233
234 tracing::trace_span!("encrypting attachment").in_scope(|| {
235 crate::attachment_cipher::encrypt_in_place(iv, key, &mut contents)
236 });
237
238 let attachment_upload_form = self
242 .service
243 .get_attachment_v4_upload_attributes()
244 .instrument(tracing::trace_span!("requesting upload attributes"))
245 .await?;
246
247 let resumable_upload_url = self
248 .service
249 .get_attachment_resumable_upload_url(&attachment_upload_form)
250 .await?;
251
252 let attachment_digest = self
253 .service
254 .upload_attachment_v4(
255 attachment_upload_form.cdn,
256 &resumable_upload_url,
257 contents.len() as u64,
258 attachment_upload_form.headers,
259 &mut std::io::Cursor::new(&contents),
260 )
261 .await?;
262
263 Ok(AttachmentPointer {
264 content_type: Some(spec.content_type),
265 key: Some(key.to_vec()),
266 size: Some(len as u32),
267 digest: Some(attachment_digest.digest),
269 file_name: spec.file_name,
270 flags: Some(
271 if spec.voice_note == Some(true) {
272 AttachmentPointerFlags::VoiceMessage as u32
273 } else {
274 0
275 } | if spec.borderless == Some(true) {
276 AttachmentPointerFlags::Borderless as u32
277 } else {
278 0
279 },
280 ),
281 width: spec.width,
282 height: spec.height,
283 caption: spec.caption,
284 blur_hash: spec.blur_hash,
285 upload_timestamp: Some(
286 SystemTime::now()
287 .duration_since(SystemTime::UNIX_EPOCH)
288 .expect("unix epoch in the past")
289 .as_millis() as u64,
290 ),
291 cdn_number: Some(attachment_upload_form.cdn),
292 attachment_identifier: Some(AttachmentIdentifier::CdnKey(
293 attachment_upload_form.key,
294 )),
295 ..Default::default()
296 })
297 }
298
299 #[tracing::instrument(skip(self, contacts))]
303 async fn upload_contact_details<Contacts>(
304 &mut self,
305 contacts: Contacts,
306 ) -> Result<AttachmentPointer, AttachmentUploadError>
307 where
308 Contacts: IntoIterator<Item = ContactDetails>,
309 {
310 use prost::Message;
311 let mut out = Vec::new();
312 for contact in contacts {
313 contact
314 .encode_length_delimited(&mut out)
315 .expect("infallible encoding");
316 }
318
319 let spec = AttachmentSpec {
320 content_type: "application/octet-stream".into(),
321 length: out.len(),
322 file_name: None,
323 preview: None,
324 voice_note: None,
325 borderless: None,
326 width: None,
327 height: None,
328 caption: None,
329 blur_hash: None,
330 };
331 self.upload_attachment(spec, out, &mut rng()).await
332 }
333
334 async fn is_multi_device(&self) -> bool {
339 if self.device_id == *DEFAULT_DEVICE_ID {
340 self.protocol_store
341 .get_sub_device_sessions(&self.local_aci.into())
342 .await
343 .is_ok_and(|s| !s.is_empty())
344 } else {
345 true
346 }
347 }
348
349 #[tracing::instrument(
351 skip(self, unidentified_access, message),
352 fields(unidentified_access = unidentified_access.is_some(), recipient = recipient.service_id_string()),
353 )]
354 pub async fn send_message(
355 &mut self,
356 recipient: &ServiceId,
357 mut unidentified_access: Option<&UnidentifiedAccess>,
358 message: impl Into<ContentBody>,
359 timestamp: u64,
360 include_pni_signature: bool,
361 online: bool,
362 ) -> SendMessageResult {
363 let content_body = message.into();
364 let message_to_self = recipient == &self.local_aci;
365 let sync_message =
366 matches!(content_body, ContentBody::SynchronizeMessage(..));
367 let is_multi_device = self.is_multi_device().await;
368
369 if message_to_self && is_multi_device && !sync_message {
371 debug!("sending note to self");
372 if let Some(sync_message) = self
373 .create_multi_device_sent_transcript_content(
374 Some(recipient),
375 content_body,
376 timestamp,
377 None,
378 )
379 {
380 return self
381 .try_send_message(
382 *recipient,
383 None,
384 &sync_message,
385 timestamp,
386 include_pni_signature,
387 online,
388 )
389 .await;
390 } else {
391 error!("could not create sync message from message to self");
392 return SendMessageResult::Err(
393 MessageSenderError::NoMessagesToSend,
394 );
395 }
396 }
397
398 if sync_message {
400 unidentified_access.take();
401 }
402
403 let result = self
405 .try_send_message(
406 *recipient,
407 unidentified_access,
408 &content_body,
409 timestamp,
410 include_pni_signature,
411 online,
412 )
413 .await;
414
415 let needs_sync = match &result {
416 Ok(SentMessage { needs_sync, .. }) => *needs_sync,
417 _ => false,
418 };
419
420 if needs_sync || is_multi_device {
421 let sync_body = if sync_message {
422 Some(content_body)
423 } else {
424 self.create_multi_device_sent_transcript_content(
427 Some(recipient),
428 content_body,
429 timestamp,
430 Some(&result),
431 )
432 };
433 if let Some(body) = sync_body {
434 debug!("sending multi-device sync message");
435 self.try_send_message(
436 self.local_aci.into(),
437 None,
438 &body,
439 timestamp,
440 false,
441 false,
442 )
443 .await?;
444 }
445 }
446
447 result
448 }
449
450 #[tracing::instrument(
457 skip(self, recipients, message),
458 fields(recipients = recipients.as_ref().len()),
459 )]
460 pub async fn send_message_to_group(
461 &mut self,
462 recipients: impl AsRef<[(ServiceId, Option<UnidentifiedAccess>, bool)]>,
463 message: impl Into<ContentBody>,
464 timestamp: u64,
465 online: bool,
466 ) -> Vec<SendMessageResult> {
467 let content_body: ContentBody = message.into();
468 let mut results = vec![];
469
470 let mut needs_sync_in_results = false;
471
472 for (recipient, unidentified_access, include_pni_signature) in
473 recipients.as_ref()
474 {
475 let result = self
476 .try_send_message(
477 *recipient,
478 unidentified_access.as_ref(),
479 &content_body,
480 timestamp,
481 *include_pni_signature,
482 online,
483 )
484 .await;
485
486 match result {
487 Ok(SentMessage { needs_sync, .. }) if needs_sync => {
488 needs_sync_in_results = true;
489 },
490 _ => (),
491 };
492
493 results.push(result);
494 }
495
496 if needs_sync_in_results || self.is_multi_device().await {
498 if let Some(sync_message) = self
499 .create_multi_device_sent_transcript_content(
500 None,
501 content_body.clone(),
502 timestamp,
503 &results,
504 )
505 {
506 if let Err(error) = self
509 .try_send_message(
510 self.local_aci.into(),
511 None,
512 &sync_message,
513 timestamp,
514 false, false,
516 )
517 .await
518 {
519 error!(%error, "failed to send a synchronization message");
520 }
521 } else {
522 error!("could not create sync message from a group message")
523 }
524 }
525
526 results
527 }
528
529 #[tracing::instrument(
543 skip(self, unidentified_access),
544 fields(recipient = recipient.service_id_string(), unidentified_send = unidentified_access.is_some(), failed_timestamp),
545 )]
546 pub async fn send_sender_key_decryption_error_message(
547 &mut self,
548 recipient: &ServiceId,
549 unidentified_access: Option<&UnidentifiedAccess>,
550 failed_timestamp: u64,
551 failed_device: DeviceId,
552 ) -> Result<(), MessageSenderError> {
553 info!("sending retry receipt/decryption error");
554
555 let content_body = ContentBody::DecryptionErrorMessage(
565 crate::proto::DecryptionErrorMessage {
566 ratchet_key: None,
567 timestamp: Some(failed_timestamp),
568 device_id: Some(failed_device.into()),
569 },
570 );
571
572 self.try_send_message(
573 *recipient,
574 unidentified_access,
575 &content_body,
576 Utc::now().timestamp_millis() as u64,
577 false,
578 false,
579 )
580 .await?;
581
582 Ok(())
583 }
584
585 #[tracing::instrument(
587 level = "trace",
588 skip(self, unidentified_access, content_body, recipient),
589 fields(unidentified_access = unidentified_access.is_some(), recipient = recipient.service_id_string()),
590 )]
591 async fn try_send_message(
592 &mut self,
593 recipient: ServiceId,
594 mut unidentified_access: Option<&UnidentifiedAccess>,
595 content_body: &ContentBody,
596 timestamp: u64,
597 include_pni_signature: bool,
598 online: bool,
599 ) -> SendMessageResult {
600 trace!("trying to send a message");
601
602 use prost::Message;
603
604 let mut content = content_body.clone().into_proto();
605 if include_pni_signature {
606 content.pni_signature_message = Some(self.create_pni_signature()?);
607 }
608
609 let content_bytes = content.encode_to_vec();
610
611 let mut rng = rng();
612
613 for _ in 0..4u8 {
614 let Some(EncryptedMessages {
615 messages,
616 used_identity_key,
617 }) = self
618 .create_encrypted_messages(
619 &recipient,
620 unidentified_access.map(|x| &x.certificate),
621 &content_bytes,
622 )
623 .await?
624 else {
625 return Err(MessageSenderError::NoMessagesToSend);
629 };
630
631 let messages = OutgoingPushMessages {
632 destination: recipient,
633 timestamp,
634 messages,
635 online,
636 };
637
638 let send = if let Some(unidentified) = &unidentified_access {
639 tracing::debug!("sending via unidentified");
640 self.unidentified_ws
641 .send_messages_unidentified(messages, unidentified)
642 .await
643 } else {
644 tracing::debug!("sending identified");
645 self.identified_ws.send_messages(messages).await
646 };
647
648 match send {
649 Ok(SendMessageResponse { needs_sync }) => {
650 tracing::debug!("message sent!");
651 return Ok(SentMessage {
652 recipient,
653 used_identity_key,
654 unidentified: unidentified_access.is_some(),
655 needs_sync,
656 });
657 },
658 Err(ServiceError::Unauthorized)
659 if unidentified_access.is_some() =>
660 {
661 tracing::trace!("unauthorized error using unidentified; retry over identified");
662 unidentified_access = None;
663 },
664 Err(ServiceError::MismatchedDevicesException(ref m)) => {
665 tracing::debug!("{:?}", m);
666 for extra_device_id in &m.extra_devices {
667 tracing::debug!(
668 "dropping session with device {}",
669 extra_device_id
670 );
671 self.protocol_store
672 .delete_service_addr_device_session(
673 &recipient
674 .to_protocol_address(*extra_device_id)?,
675 )
676 .await?;
677 }
678
679 for missing_device_id in &m.missing_devices {
680 tracing::debug!(
681 "creating session with missing device {}",
682 missing_device_id
683 );
684 let remote_address = recipient
685 .to_protocol_address(*missing_device_id)?;
686 let pre_key = self
687 .identified_ws
688 .get_pre_key(&recipient, *missing_device_id)
689 .await?;
690
691 process_prekey_bundle(
692 &remote_address,
693 &self
694 .local_aci
695 .to_protocol_address(self.device_id)
696 .expect("valid device id"),
697 &mut self.protocol_store.clone(),
698 &mut self.protocol_store,
699 &pre_key,
700 SystemTime::now(),
701 &mut rng,
702 )
703 .await
704 .map_err(|e| {
705 error!("failed to create session: {}", e);
706 MessageSenderError::UntrustedIdentity {
707 address: recipient,
708 }
709 })?;
710 }
711 },
712 Err(ServiceError::StaleDevices(ref m)) => {
713 tracing::debug!("{:?}", m);
714 for extra_device_id in &m.stale_devices {
715 tracing::debug!(
716 "dropping session with device {}",
717 extra_device_id
718 );
719 self.protocol_store
720 .delete_service_addr_device_session(
721 &recipient
722 .to_protocol_address(*extra_device_id)?,
723 )
724 .await?;
725 }
726 },
727 Err(ServiceError::ProofRequiredError(ref p)) => {
728 tracing::debug!("{:?}", p);
729 return Err(MessageSenderError::ProofRequired {
730 token: p.token.clone(),
731 options: p.options.clone(),
732 });
733 },
734 Err(ServiceError::UnregisteredRecipient) => {
735 tracing::debug!(?recipient, "recipient is not registered");
736 return Err(MessageSenderError::NotFound {
737 service_id: recipient,
738 });
739 },
740 Err(e) => {
741 tracing::debug!(
742 "Default error handler for ws.send_messages: {}",
743 e
744 );
745 return Err(MessageSenderError::ServiceError(e));
746 },
747 }
748 }
749
750 Err(MessageSenderError::MaximumRetriesLimitExceeded)
751 }
752
753 #[tracing::instrument(
755 skip(self, unidentified_access, contacts, recipient),
756 fields(unidentified_access = unidentified_access.is_some(), recipient = recipient.service_id_string()),
757 )]
758 pub async fn send_contact_details<Contacts>(
759 &mut self,
760 recipient: &ServiceId,
761 unidentified_access: Option<UnidentifiedAccess>,
762 contacts: Contacts,
766 online: bool,
767 complete: bool,
768 ) -> Result<(), MessageSenderError>
769 where
770 Contacts: IntoIterator<Item = ContactDetails>,
771 {
772 let ptr = self.upload_contact_details(contacts).await?;
773
774 let msg = SyncMessage {
775 content: Some(crate::proto::sync_message::Content::Contacts(
776 sync_message::Contacts {
777 blob: Some(ptr),
778 complete: Some(complete),
779 },
780 )),
781 ..SyncMessage::with_padding(&mut rng())
782 };
783
784 self.send_sync_message(msg).await?;
785
786 Ok(())
787 }
788
789 #[tracing::instrument(skip(self), fields(recipient = recipient.service_id_string()))]
791 pub async fn send_message_request_response(
792 &mut self,
793 recipient: &ServiceId,
794 thread: &ThreadIdentifier,
795 action: message_request_response::Type,
796 ) -> Result<(), MessageSenderError> {
797 let message_request_response = match thread {
798 ThreadIdentifier::Aci(aci) => {
799 tracing::debug!(
800 "sending message request response {:?} for recipient {:?}",
801 action,
802 aci
803 );
804 MessageRequestResponse {
805 thread_aci: Some(aci.to_string()),
806 thread_aci_binary: Some(aci.into_bytes().to_vec()),
807 group_id: None,
808 r#type: Some(action.into()),
809 }
810 },
811 ThreadIdentifier::Group(id) => {
812 tracing::debug!(
813 "sending message request response {:?} for group {:?}",
814 action,
815 id
816 );
817 MessageRequestResponse {
818 thread_aci: None,
819 thread_aci_binary: None,
820 group_id: Some(id.to_vec()),
821 r#type: Some(action.into()),
822 }
823 },
824 };
825
826 let msg = SyncMessage {
827 content: Some(
828 crate::proto::sync_message::Content::MessageRequestResponse(
829 message_request_response,
830 ),
831 ),
832 ..SyncMessage::with_padding(&mut rng())
833 };
834
835 let ts = Utc::now().timestamp_millis() as u64;
836 self.send_message(recipient, None, msg, ts, false, false)
837 .await?;
838
839 Ok(())
840 }
841
842 pub async fn send_sync_message(
844 &mut self,
845 sync: impl Into<SyncMessage>,
846 ) -> Result<(), MessageSenderError> {
847 if self.is_multi_device().await {
848 let content = sync.into().into();
849 let timestamp = Utc::now().timestamp_millis() as u64;
850 debug!(
851 "sending multi-device sync message with content {content:?}"
852 );
853 self.try_send_message(
854 self.local_aci.into(),
855 None,
856 &content,
857 timestamp,
858 false,
859 false,
860 )
861 .await?;
862 }
863 Ok(())
864 }
865
866 #[tracing::instrument(skip(self))]
868 pub async fn send_sync_message_request(
869 &mut self,
870 recipient: &ServiceId,
871 request_type: sync_message::request::Type,
872 ) -> Result<(), MessageSenderError> {
873 if self.device_id == *DEFAULT_DEVICE_ID {
874 return Err(MessageSenderError::SendSyncMessageError(request_type));
875 }
876
877 let msg = SyncMessage {
878 content: Some(crate::proto::sync_message::Content::Request(
879 sync_message::Request {
880 r#type: Some(request_type.into()),
881 },
882 )),
883 ..SyncMessage::with_padding(&mut rng())
884 };
885 self.send_sync_message(msg).await?;
886
887 Ok(())
888 }
889
890 #[tracing::instrument(level = "trace", skip(self))]
891 fn create_pni_signature(
892 &mut self,
893 ) -> Result<crate::proto::PniSignatureMessage, MessageSenderError> {
894 let mut rng = rng();
895 let signature = self
896 .pni_identity
897 .expect("PNI key set when PNI signature requested")
898 .sign_alternate_identity(
899 self.aci_identity.identity_key(),
900 &mut rng,
901 )?;
902 Ok(crate::proto::PniSignatureMessage {
903 pni: Some(self.local_pni.service_id_binary()),
904 signature: Some(signature.into()),
905 })
906 }
907
908 #[tracing::instrument(
910 level = "trace",
911 skip(self, unidentified_access, content),
912 fields(unidentified_access = unidentified_access.is_some(), recipient = recipient.service_id_string()),
913 )]
914 async fn create_encrypted_messages(
915 &mut self,
916 recipient: &ServiceId,
917 unidentified_access: Option<&SenderCertificate>,
918 content: &[u8],
919 ) -> Result<Option<EncryptedMessages>, MessageSenderError> {
920 let mut messages = vec![];
921
922 let mut devices: HashSet<DeviceId> = self
923 .protocol_store
924 .get_sub_device_sessions(recipient)
925 .await?
926 .into_iter()
927 .collect();
928
929 devices.insert(*DEFAULT_DEVICE_ID);
931
932 match recipient {
934 ServiceId::Aci(aci) => {
935 if *aci == self.local_aci {
936 devices.remove(&self.device_id);
937 }
938 },
939 ServiceId::Pni(pni) => {
940 if *pni == self.local_pni {
941 devices.remove(&self.device_id);
942 }
943 },
944 };
945
946 for device_id in devices {
947 trace!("sending message to device {}", device_id);
948 for _attempt in 0..2 {
952 match self
953 .create_encrypted_message(
954 recipient,
955 unidentified_access,
956 device_id,
957 content,
958 )
959 .await
960 {
961 Ok(message) => {
962 messages.push(message);
963 break;
964 },
965 Err(MessageSenderError::ServiceError(
966 ServiceError::SignalProtocolError(
967 SignalProtocolError::SessionNotFound(
968 SessionNotFound {
969 address: Some(addr),
970 op,
971 },
972 ),
973 ),
974 )) => {
975 tracing::warn!("Potential session corruption for {}, deleting session", addr);
980 match self.protocol_store.delete_session(&addr).await {
981 Ok(()) => continue,
982 Err(error) => {
983 tracing::warn!(%error, %addr, "failed to delete session");
984 return Err(
985 SignalProtocolError::SessionNotFound(
986 SessionNotFound::new(addr, op),
987 )
988 .into(),
989 );
990 },
991 }
992 },
993 Err(e) => return Err(e),
994 }
995 }
996 }
997
998 if messages.is_empty() {
999 Ok(None)
1000 } else {
1001 Ok(Some(EncryptedMessages {
1002 messages,
1003 used_identity_key: self
1004 .protocol_store
1005 .get_identity(
1006 &recipient.to_protocol_address(*DEFAULT_DEVICE_ID),
1007 )
1008 .await?
1009 .ok_or(MessageSenderError::UntrustedIdentity {
1010 address: *recipient,
1011 })?,
1012 }))
1013 }
1014 }
1015
1016 #[tracing::instrument(
1020 level = "trace",
1021 skip(self, unidentified_access, content),
1022 fields(unidentified_access = unidentified_access.is_some(), recipient = recipient.service_id_string()),
1023 )]
1024 pub(crate) async fn create_encrypted_message(
1025 &mut self,
1026 recipient: &ServiceId,
1027 unidentified_access: Option<&SenderCertificate>,
1028 device_id: DeviceId,
1029 content: &[u8],
1030 ) -> Result<OutgoingPushMessage, MessageSenderError> {
1031 let recipient_protocol_address =
1032 recipient.to_protocol_address(device_id);
1033
1034 tracing::trace!(
1035 "encrypting message for {}",
1036 recipient_protocol_address
1037 );
1038
1039 if self
1042 .protocol_store
1043 .load_session(&recipient_protocol_address)
1044 .await?
1045 .is_none()
1046 {
1047 info!(
1048 "establishing new session with {}",
1049 recipient_protocol_address
1050 );
1051 let pre_keys = match self
1052 .identified_ws
1053 .get_pre_keys(recipient, device_id)
1054 .await
1055 {
1056 Ok(ok) => {
1057 tracing::trace!("Get prekeys OK");
1058 ok
1059 },
1060 Err(ServiceError::NotFoundError) => {
1061 return Err(MessageSenderError::NotFound {
1062 service_id: *recipient,
1063 });
1064 },
1065 Err(e) => Err(e)?,
1066 };
1067
1068 let mut rng = rng();
1069
1070 for pre_key_bundle in pre_keys {
1071 if recipient == &self.local_aci
1072 && self.device_id == pre_key_bundle.device_id()?
1073 {
1074 trace!("not establishing a session with myself!");
1075 continue;
1076 }
1077
1078 let pre_key_address = get_preferred_protocol_address(
1079 &self.protocol_store,
1080 recipient,
1081 pre_key_bundle.device_id()?,
1082 )
1083 .await?;
1084
1085 process_prekey_bundle(
1086 &pre_key_address,
1087 &self
1088 .local_aci
1089 .to_protocol_address(self.device_id)
1090 .expect("valid device id"),
1091 &mut self.protocol_store.clone(),
1092 &mut self.protocol_store,
1093 &pre_key_bundle,
1094 SystemTime::now(),
1095 &mut rng,
1096 )
1097 .await?;
1098 }
1099 }
1100
1101 let message = self
1102 .cipher
1103 .encrypt(
1104 &recipient_protocol_address,
1105 unidentified_access,
1106 content,
1107 &mut rng(),
1108 )
1109 .instrument(tracing::trace_span!("encrypting message"))
1110 .await?;
1111
1112 Ok(message)
1113 }
1114
1115 fn create_multi_device_sent_transcript_content<'a>(
1116 &mut self,
1117 recipient: Option<&ServiceId>,
1118 content_body: ContentBody,
1119 timestamp: u64,
1120 send_message_results: impl IntoIterator<Item = &'a SendMessageResult>,
1121 ) -> Option<ContentBody> {
1122 use sync_message::sent::UnidentifiedDeliveryStatus;
1123 let (message, edit_message) = match content_body {
1124 ContentBody::DataMessage(m) => (Some(m), None),
1125 ContentBody::EditMessage(m) => (None, Some(m)),
1126 content_body => {
1127 tracing::trace!(?content_body, "not syncing to self");
1128 return None;
1129 },
1130 };
1131 let unidentified_status: Vec<UnidentifiedDeliveryStatus> =
1132 send_message_results
1133 .into_iter()
1134 .filter_map(|result| result.as_ref().ok())
1135 .map(|sent| {
1136 let SentMessage {
1137 recipient,
1138 unidentified,
1139 used_identity_key,
1140 ..
1141 } = sent;
1142 UnidentifiedDeliveryStatus {
1143 destination_service_id: Some(
1144 recipient.service_id_string(),
1145 ),
1146 destination_service_id_binary: Some(
1147 recipient.service_id_binary(),
1148 ),
1149 unidentified: Some(*unidentified),
1150 destination_pni_identity_key: Some(
1151 used_identity_key.serialize().into(),
1152 ),
1153 }
1154 })
1155 .collect();
1156 Some(ContentBody::SynchronizeMessage(SyncMessage {
1157 content: Some(sync_message::Content::Sent(sync_message::Sent {
1158 destination_service_id: recipient
1159 .map(ServiceId::service_id_string),
1160 destination_service_id_binary: recipient
1161 .map(ServiceId::service_id_binary),
1162 destination_e164: None,
1163 expiration_start_timestamp: message
1164 .as_ref()
1165 .and_then(|m| m.expire_timer)
1166 .map(|_| timestamp),
1167 message,
1168 edit_message,
1169 timestamp: Some(timestamp),
1170 unidentified_status,
1171 ..Default::default()
1172 })),
1173 ..SyncMessage::with_padding(&mut rng())
1174 }))
1175 }
1176}