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.as_ref(),
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(
531 level = "trace",
532 skip(self, unidentified_access, content_body, recipient),
533 fields(unidentified_access = unidentified_access.is_some(), recipient = recipient.service_id_string()),
534 )]
535 async fn try_send_message(
536 &mut self,
537 recipient: ServiceId,
538 mut unidentified_access: Option<&UnidentifiedAccess>,
539 content_body: &ContentBody,
540 timestamp: u64,
541 include_pni_signature: bool,
542 online: bool,
543 ) -> SendMessageResult {
544 trace!("trying to send a message");
545
546 use prost::Message;
547
548 let mut content = content_body.clone().into_proto();
549 if include_pni_signature {
550 content.pni_signature_message = Some(self.create_pni_signature()?);
551 }
552
553 let content_bytes = content.encode_to_vec();
554
555 let mut rng = rng();
556
557 for _ in 0..4u8 {
558 let Some(EncryptedMessages {
559 messages,
560 used_identity_key,
561 }) = self
562 .create_encrypted_messages(
563 &recipient,
564 unidentified_access.map(|x| &x.certificate),
565 &content_bytes,
566 )
567 .await?
568 else {
569 return Err(MessageSenderError::NoMessagesToSend);
573 };
574
575 let messages = OutgoingPushMessages {
576 destination: recipient,
577 timestamp,
578 messages,
579 online,
580 };
581
582 let send = if let Some(unidentified) = &unidentified_access {
583 tracing::debug!("sending via unidentified");
584 self.unidentified_ws
585 .send_messages_unidentified(messages, unidentified)
586 .await
587 } else {
588 tracing::debug!("sending identified");
589 self.identified_ws.send_messages(messages).await
590 };
591
592 match send {
593 Ok(SendMessageResponse { needs_sync }) => {
594 tracing::debug!("message sent!");
595 return Ok(SentMessage {
596 recipient,
597 used_identity_key,
598 unidentified: unidentified_access.is_some(),
599 needs_sync,
600 });
601 },
602 Err(ServiceError::Unauthorized)
603 if unidentified_access.is_some() =>
604 {
605 tracing::trace!("unauthorized error using unidentified; retry over identified");
606 unidentified_access = None;
607 },
608 Err(ServiceError::MismatchedDevicesException(ref m)) => {
609 tracing::debug!("{:?}", m);
610 for extra_device_id in &m.extra_devices {
611 tracing::debug!(
612 "dropping session with device {}",
613 extra_device_id
614 );
615 self.protocol_store
616 .delete_service_addr_device_session(
617 &recipient
618 .to_protocol_address(*extra_device_id)?,
619 )
620 .await?;
621 }
622
623 for missing_device_id in &m.missing_devices {
624 tracing::debug!(
625 "creating session with missing device {}",
626 missing_device_id
627 );
628 let remote_address = recipient
629 .to_protocol_address(*missing_device_id)?;
630 let pre_key = self
631 .identified_ws
632 .get_pre_key(&recipient, *missing_device_id)
633 .await?;
634
635 process_prekey_bundle(
636 &remote_address,
637 &self
638 .local_aci
639 .to_protocol_address(self.device_id)
640 .expect("valid device id"),
641 &mut self.protocol_store.clone(),
642 &mut self.protocol_store,
643 &pre_key,
644 SystemTime::now(),
645 &mut rng,
646 )
647 .await
648 .map_err(|e| {
649 error!("failed to create session: {}", e);
650 MessageSenderError::UntrustedIdentity {
651 address: recipient,
652 }
653 })?;
654 }
655 },
656 Err(ServiceError::StaleDevices(ref m)) => {
657 tracing::debug!("{:?}", m);
658 for extra_device_id in &m.stale_devices {
659 tracing::debug!(
660 "dropping session with device {}",
661 extra_device_id
662 );
663 self.protocol_store
664 .delete_service_addr_device_session(
665 &recipient
666 .to_protocol_address(*extra_device_id)?,
667 )
668 .await?;
669 }
670 },
671 Err(ServiceError::ProofRequiredError(ref p)) => {
672 tracing::debug!("{:?}", p);
673 return Err(MessageSenderError::ProofRequired {
674 token: p.token.clone(),
675 options: p.options.clone(),
676 });
677 },
678 Err(ServiceError::NotFoundError) => {
679 tracing::debug!("Not found when sending a message");
680 return Err(MessageSenderError::NotFound {
681 service_id: recipient,
682 });
683 },
684 Err(e) => {
685 tracing::debug!(
686 "Default error handler for ws.send_messages: {}",
687 e
688 );
689 return Err(MessageSenderError::ServiceError(e));
690 },
691 }
692 }
693
694 Err(MessageSenderError::MaximumRetriesLimitExceeded)
695 }
696
697 #[tracing::instrument(
699 skip(self, unidentified_access, contacts, recipient),
700 fields(unidentified_access = unidentified_access.is_some(), recipient = recipient.service_id_string()),
701 )]
702 pub async fn send_contact_details<Contacts>(
703 &mut self,
704 recipient: &ServiceId,
705 unidentified_access: Option<UnidentifiedAccess>,
706 contacts: Contacts,
710 online: bool,
711 complete: bool,
712 ) -> Result<(), MessageSenderError>
713 where
714 Contacts: IntoIterator<Item = ContactDetails>,
715 {
716 let ptr = self.upload_contact_details(contacts).await?;
717
718 let msg = SyncMessage {
719 content: Some(crate::proto::sync_message::Content::Contacts(
720 sync_message::Contacts {
721 blob: Some(ptr),
722 complete: Some(complete),
723 },
724 )),
725 ..SyncMessage::with_padding(&mut rng())
726 };
727
728 self.send_sync_message(msg).await?;
729
730 Ok(())
731 }
732
733 #[tracing::instrument(skip(self), fields(recipient = recipient.service_id_string()))]
735 pub async fn send_message_request_response(
736 &mut self,
737 recipient: &ServiceId,
738 thread: &ThreadIdentifier,
739 action: message_request_response::Type,
740 ) -> Result<(), MessageSenderError> {
741 let message_request_response = match thread {
742 ThreadIdentifier::Aci(aci) => {
743 tracing::debug!(
744 "sending message request response {:?} for recipient {:?}",
745 action,
746 aci
747 );
748 MessageRequestResponse {
749 thread_aci: Some(aci.to_string()),
750 thread_aci_binary: Some(aci.into_bytes().to_vec()),
751 group_id: None,
752 r#type: Some(action.into()),
753 }
754 },
755 ThreadIdentifier::Group(id) => {
756 tracing::debug!(
757 "sending message request response {:?} for group {:?}",
758 action,
759 id
760 );
761 MessageRequestResponse {
762 thread_aci: None,
763 thread_aci_binary: None,
764 group_id: Some(id.to_vec()),
765 r#type: Some(action.into()),
766 }
767 },
768 };
769
770 let msg = SyncMessage {
771 content: Some(
772 crate::proto::sync_message::Content::MessageRequestResponse(
773 message_request_response,
774 ),
775 ),
776 ..SyncMessage::with_padding(&mut rng())
777 };
778
779 let ts = Utc::now().timestamp_millis() as u64;
780 self.send_message(recipient, None, msg, ts, false, false)
781 .await?;
782
783 Ok(())
784 }
785
786 pub async fn send_sync_message(
788 &mut self,
789 sync: impl Into<SyncMessage>,
790 ) -> Result<(), MessageSenderError> {
791 if self.is_multi_device().await {
792 let content = sync.into().into();
793 let timestamp = Utc::now().timestamp_millis() as u64;
794 debug!(
795 "sending multi-device sync message with content {content:?}"
796 );
797 self.try_send_message(
798 self.local_aci.into(),
799 None,
800 &content,
801 timestamp,
802 false,
803 false,
804 )
805 .await?;
806 }
807 Ok(())
808 }
809
810 #[tracing::instrument(skip(self))]
812 pub async fn send_sync_message_request(
813 &mut self,
814 recipient: &ServiceId,
815 request_type: sync_message::request::Type,
816 ) -> Result<(), MessageSenderError> {
817 if self.device_id == *DEFAULT_DEVICE_ID {
818 return Err(MessageSenderError::SendSyncMessageError(request_type));
819 }
820
821 let msg = SyncMessage {
822 content: Some(crate::proto::sync_message::Content::Request(
823 sync_message::Request {
824 r#type: Some(request_type.into()),
825 },
826 )),
827 ..SyncMessage::with_padding(&mut rng())
828 };
829 self.send_sync_message(msg).await?;
830
831 Ok(())
832 }
833
834 #[tracing::instrument(level = "trace", skip(self))]
835 fn create_pni_signature(
836 &mut self,
837 ) -> Result<crate::proto::PniSignatureMessage, MessageSenderError> {
838 let mut rng = rng();
839 let signature = self
840 .pni_identity
841 .expect("PNI key set when PNI signature requested")
842 .sign_alternate_identity(
843 self.aci_identity.identity_key(),
844 &mut rng,
845 )?;
846 Ok(crate::proto::PniSignatureMessage {
847 pni: Some(self.local_pni.service_id_binary()),
848 signature: Some(signature.into()),
849 })
850 }
851
852 #[tracing::instrument(
854 level = "trace",
855 skip(self, unidentified_access, content),
856 fields(unidentified_access = unidentified_access.is_some(), recipient = recipient.service_id_string()),
857 )]
858 async fn create_encrypted_messages(
859 &mut self,
860 recipient: &ServiceId,
861 unidentified_access: Option<&SenderCertificate>,
862 content: &[u8],
863 ) -> Result<Option<EncryptedMessages>, MessageSenderError> {
864 let mut messages = vec![];
865
866 let mut devices: HashSet<DeviceId> = self
867 .protocol_store
868 .get_sub_device_sessions(recipient)
869 .await?
870 .into_iter()
871 .collect();
872
873 devices.insert(*DEFAULT_DEVICE_ID);
875
876 match recipient {
878 ServiceId::Aci(aci) => {
879 if *aci == self.local_aci {
880 devices.remove(&self.device_id);
881 }
882 },
883 ServiceId::Pni(pni) => {
884 if *pni == self.local_pni {
885 devices.remove(&self.device_id);
886 }
887 },
888 };
889
890 for device_id in devices {
891 trace!("sending message to device {}", device_id);
892 for _attempt in 0..2 {
896 match self
897 .create_encrypted_message(
898 recipient,
899 unidentified_access,
900 device_id,
901 content,
902 )
903 .await
904 {
905 Ok(message) => {
906 messages.push(message);
907 break;
908 },
909 Err(MessageSenderError::ServiceError(
910 ServiceError::SignalProtocolError(
911 SignalProtocolError::SessionNotFound(
912 SessionNotFound {
913 address: Some(addr),
914 op,
915 },
916 ),
917 ),
918 )) => {
919 tracing::warn!("Potential session corruption for {}, deleting session", addr);
924 match self.protocol_store.delete_session(&addr).await {
925 Ok(()) => continue,
926 Err(error) => {
927 tracing::warn!(%error, %addr, "failed to delete session");
928 return Err(
929 SignalProtocolError::SessionNotFound(
930 SessionNotFound::new(addr, op),
931 )
932 .into(),
933 );
934 },
935 }
936 },
937 Err(e) => return Err(e),
938 }
939 }
940 }
941
942 if messages.is_empty() {
943 Ok(None)
944 } else {
945 Ok(Some(EncryptedMessages {
946 messages,
947 used_identity_key: self
948 .protocol_store
949 .get_identity(
950 &recipient.to_protocol_address(*DEFAULT_DEVICE_ID),
951 )
952 .await?
953 .ok_or(MessageSenderError::UntrustedIdentity {
954 address: *recipient,
955 })?,
956 }))
957 }
958 }
959
960 #[tracing::instrument(
964 level = "trace",
965 skip(self, unidentified_access, content),
966 fields(unidentified_access = unidentified_access.is_some(), recipient = recipient.service_id_string()),
967 )]
968 pub(crate) async fn create_encrypted_message(
969 &mut self,
970 recipient: &ServiceId,
971 unidentified_access: Option<&SenderCertificate>,
972 device_id: DeviceId,
973 content: &[u8],
974 ) -> Result<OutgoingPushMessage, MessageSenderError> {
975 let recipient_protocol_address =
976 recipient.to_protocol_address(device_id);
977
978 tracing::trace!(
979 "encrypting message for {}",
980 recipient_protocol_address
981 );
982
983 if self
986 .protocol_store
987 .load_session(&recipient_protocol_address)
988 .await?
989 .is_none()
990 {
991 info!(
992 "establishing new session with {}",
993 recipient_protocol_address
994 );
995 let pre_keys = match self
996 .identified_ws
997 .get_pre_keys(recipient, device_id)
998 .await
999 {
1000 Ok(ok) => {
1001 tracing::trace!("Get prekeys OK");
1002 ok
1003 },
1004 Err(ServiceError::NotFoundError) => {
1005 return Err(MessageSenderError::NotFound {
1006 service_id: *recipient,
1007 });
1008 },
1009 Err(e) => Err(e)?,
1010 };
1011
1012 let mut rng = rng();
1013
1014 for pre_key_bundle in pre_keys {
1015 if recipient == &self.local_aci
1016 && self.device_id == pre_key_bundle.device_id()?
1017 {
1018 trace!("not establishing a session with myself!");
1019 continue;
1020 }
1021
1022 let pre_key_address = get_preferred_protocol_address(
1023 &self.protocol_store,
1024 recipient,
1025 pre_key_bundle.device_id()?,
1026 )
1027 .await?;
1028
1029 process_prekey_bundle(
1030 &pre_key_address,
1031 &self
1032 .local_aci
1033 .to_protocol_address(self.device_id)
1034 .expect("valid device id"),
1035 &mut self.protocol_store.clone(),
1036 &mut self.protocol_store,
1037 &pre_key_bundle,
1038 SystemTime::now(),
1039 &mut rng,
1040 )
1041 .await?;
1042 }
1043 }
1044
1045 let message = self
1046 .cipher
1047 .encrypt(
1048 &recipient_protocol_address,
1049 unidentified_access,
1050 content,
1051 &mut rng(),
1052 )
1053 .instrument(tracing::trace_span!("encrypting message"))
1054 .await?;
1055
1056 Ok(message)
1057 }
1058
1059 fn create_multi_device_sent_transcript_content<'a>(
1060 &mut self,
1061 recipient: Option<&ServiceId>,
1062 content_body: ContentBody,
1063 timestamp: u64,
1064 send_message_results: impl IntoIterator<Item = &'a SendMessageResult>,
1065 ) -> Option<ContentBody> {
1066 use sync_message::sent::UnidentifiedDeliveryStatus;
1067 let (message, edit_message) = match content_body {
1068 ContentBody::DataMessage(m) => (Some(m), None),
1069 ContentBody::EditMessage(m) => (None, Some(m)),
1070 content_body => {
1071 tracing::trace!(?content_body, "not syncing to self");
1072 return None;
1073 },
1074 };
1075 let unidentified_status: Vec<UnidentifiedDeliveryStatus> =
1076 send_message_results
1077 .into_iter()
1078 .filter_map(|result| result.as_ref().ok())
1079 .map(|sent| {
1080 let SentMessage {
1081 recipient,
1082 unidentified,
1083 used_identity_key,
1084 ..
1085 } = sent;
1086 UnidentifiedDeliveryStatus {
1087 destination_service_id: Some(
1088 recipient.service_id_string(),
1089 ),
1090 destination_service_id_binary: Some(
1091 recipient.service_id_binary(),
1092 ),
1093 unidentified: Some(*unidentified),
1094 destination_pni_identity_key: Some(
1095 used_identity_key.serialize().into(),
1096 ),
1097 }
1098 })
1099 .collect();
1100 Some(ContentBody::SynchronizeMessage(SyncMessage {
1101 content: Some(sync_message::Content::Sent(sync_message::Sent {
1102 destination_service_id: recipient
1103 .map(ServiceId::service_id_string),
1104 destination_service_id_binary: recipient
1105 .map(ServiceId::service_id_binary),
1106 destination_e164: None,
1107 expiration_start_timestamp: message
1108 .as_ref()
1109 .and_then(|m| m.expire_timer)
1110 .map(|_| timestamp),
1111 message,
1112 edit_message,
1113 timestamp: Some(timestamp),
1114 unidentified_status,
1115 ..Default::default()
1116 })),
1117 ..SyncMessage::with_padding(&mut rng())
1118 }))
1119 }
1120}