1use super::*;
2
3impl ProtocolEngine {
4 pub fn message_targets_another_device(&self, event: &Event) -> bool {
7 if event.kind.as_u16() as u32 != MESSAGE_EVENT_KIND
8 || !protocol_event_has_tag(event, "header")
9 {
10 return false;
11 }
12 let mut has_recipient = false;
13 for recipient in event.tags.public_keys() {
14 has_recipient = true;
15 if *recipient == self.owner_pubkey || ndr_device(*recipient) == self.local_device {
16 return false;
17 }
18 }
19 has_recipient
20 }
21
22 pub(super) fn invalidate_pending_inbound_retry_deadline(&self) {
23 self.pending_inbound_retry_deadline.set(None);
24 }
25
26 fn refresh_pending_inbound_retry_deadline(&self) -> PendingInboundRetryDeadline {
27 let deadline = PendingInboundRetryDeadline {
28 queue_len: self.pending_inbound.len(),
29 next_retry_at_secs: self
30 .pending_inbound
31 .iter()
32 .map(|pending| {
33 #[cfg(test)]
34 tests::record_inbound_retry_deadline_scan();
35 pending.next_retry_at_secs
36 })
37 .min(),
38 };
39 self.pending_inbound_retry_deadline.set(Some(deadline));
40 deadline
41 }
42
43 pub(super) fn has_due_pending_inbound_retry(&self, now: NdrUnixSeconds) -> bool {
44 let deadline = self
45 .pending_inbound_retry_deadline
46 .get()
47 .filter(|deadline| deadline.queue_len == self.pending_inbound.len())
48 .unwrap_or_else(|| self.refresh_pending_inbound_retry_deadline());
49 deadline
50 .next_retry_at_secs
51 .is_some_and(|next_retry| next_retry <= now.get())
52 }
53
54 pub(super) fn invalidate_pending_group_fanout_retry_deadline(&self) {
55 self.pending_group_fanout_retry_deadline.set(None);
56 }
57
58 pub(super) fn has_due_pending_group_fanout_retry(&self, now: NdrUnixSeconds) -> bool {
59 if let Some(deadline) = self
60 .pending_group_fanout_retry_deadline
61 .get()
62 .filter(|deadline| deadline.queue_len == self.pending_group_fanouts.len())
63 {
64 return deadline
65 .next_retry_at_secs
66 .is_some_and(|next_retry| next_retry <= now.get());
67 }
68 let mut next_retry_at_secs: Option<u64> = None;
69 for pending in &self.pending_group_fanouts {
70 #[cfg(test)]
71 tests::record_fanout_retry_deadline_scan();
72 let next_retry = pending.next_retry_at_secs;
73 if next_retry <= now.get() {
76 return true;
77 }
78 next_retry_at_secs =
79 Some(next_retry_at_secs.map_or(next_retry, |earliest| earliest.min(next_retry)));
80 }
81 self.pending_group_fanout_retry_deadline
82 .set(Some(PendingGroupFanoutRetryDeadline {
83 queue_len: self.pending_group_fanouts.len(),
84 next_retry_at_secs,
85 }));
86 false
87 }
88
89 pub fn has_due_pending_retry_work(&self, now: NdrUnixSeconds) -> bool {
90 if !self.pending_decrypted_deliveries.is_empty()
93 || !self.ready_group_publications.is_empty()
94 {
95 return true;
96 }
97 if !self.pending_group_sender_key_messages.is_empty() {
98 let retry = self.group_sender_key_retry.borrow();
99 if !retry.ready.is_empty() && (retry.active.is_some() || retry.prepared.is_some()) {
102 return true;
103 }
104 }
105 let now_secs = now.get();
106 self.pending_remote_sends
107 .iter()
108 .any(|pending| pending.next_retry_at_secs <= now_secs)
109 || self
110 .pending_local_sibling_sends
111 .iter()
112 .any(|pending| pending.next_retry_at_secs <= now_secs)
113 || self.has_due_pending_inbound_retry(now)
114 || self.has_due_pending_group_fanout_retry(now)
115 || self
116 .pending_group_pairwise_payloads
117 .iter()
118 .any(|pending| pending.next_retry_at_secs <= now_secs)
119 || self.pending_group_sender_key_repairs.iter().any(|pending| {
120 Self::pending_group_sender_key_repair_due_at_secs(pending) <= now_secs
121 })
122 || self.has_ready_group_sender_key_retry_work()
123 || !self.pending_decrypted_deliveries.is_empty()
124 }
125
126 pub fn process_direct_message_event(
127 &mut self,
128 event: &Event,
129 ) -> anyhow::Result<Option<ProtocolDecryptedMessage>> {
130 let envelope = parse_message_event(event)?;
131 if self.message_targets_another_device(event) {
132 return Ok(None);
133 }
134 let resolution = self.resolve_message_sender_owner(&envelope);
135 match resolution {
136 ProtocolSenderOwnerResolution::Verified { .. }
137 | ProtocolSenderOwnerResolution::ProvisionalDeviceOwner { .. } => {}
138 ProtocolSenderOwnerResolution::PendingOwnerClaim { .. } => {
139 self.queue_pending_inbound_direct_event(
140 event.clone(),
141 event.created_at.as_secs(),
142 Some(&envelope),
143 Some(resolution),
144 )?;
145 return Ok(None);
146 }
147 };
148 match self.decrypt_direct_message_envelope(event, &envelope, true) {
149 Ok(DirectReceive::Message(decrypted)) => return Ok(Some(decrypted)),
150 Ok(DirectReceive::Discarded) => return Ok(None),
151 Ok(DirectReceive::Pending) => {}
152 Err(error) => {
153 if protocol_event_has_tag(event, "header")
154 && !self.is_known_message_author(event.pubkey)
155 {
156 self.queue_pending_inbound_direct_event(
157 event.clone(),
158 event.created_at.as_secs(),
159 Some(&envelope),
160 Some(resolution),
161 )?;
162 return Ok(None);
163 }
164 return Err(error);
165 }
166 }
167 self.queue_pending_inbound_direct_event(
168 event.clone(),
169 event.created_at.as_secs(),
170 Some(&envelope),
171 Some(resolution),
172 )?;
173 Ok(None)
174 }
175
176 pub fn process_group_outer_event(
180 &mut self,
181 event: &Event,
182 ) -> anyhow::Result<ProtocolGroupIncomingResult> {
183 if self.message_targets_another_device(event) {
184 return Ok(ProtocolGroupIncomingResult {
185 consumed: true,
186 ..Default::default()
187 });
188 }
189 let has_header = protocol_event_has_tag(event, "header");
190 let parsed = if has_header {
191 parse_group_sender_key_message_event_unchecked(event)
192 } else {
193 parse_group_sender_key_message_event(event)
194 };
195 let Ok(parsed) = parsed else {
196 return Ok(ProtocolGroupIncomingResult::default());
197 };
198 let Some(message) = self.group_sender_key_message_from_parsed(&parsed) else {
199 self.queue_pending_group_sender_key_message(parsed)?;
200 return Ok(ProtocolGroupIncomingResult {
201 consumed: true,
202 ..Default::default()
203 });
204 };
205 if self
206 .processed_group_sender_key_messages
207 .contains(&group_sender_key_fingerprint(&message))
208 {
209 return Ok(ProtocolGroupIncomingResult {
210 consumed: true,
211 ..Default::default()
212 });
213 }
214 let already_pending = self.pending_group_sender_key_messages.contains(&parsed);
217 if already_pending && self.group_sender_key_message_has_pending_repair(&message) {
218 return Ok(ProtocolGroupIncomingResult {
219 consumed: true,
220 pending: true,
221 ..Default::default()
222 });
223 }
224 if !already_pending {
225 self.admit_fresh_group_sender_key_candidate(&parsed, usize::MAX);
226 }
227 let mut result = self.handle_group_sender_key_message(message)?;
228 if result.pending {
229 self.queue_group_sender_key_candidate(parsed, false)?;
231 } else if self.clear_pending_group_sender_key_candidate(&parsed) {
232 self.persist()?;
233 }
234 result.source_event_count = result.events.len();
235 if !result.pending {
236 let retry = self.retry_pending_group_inputs(NdrUnixSeconds(unix_now().get()))?;
237 result.events.extend(retry.events);
238 result.effects.extend(retry.effects);
239 }
240 Ok(ProtocolGroupIncomingResult {
241 consumed: true,
242 ..result
243 })
244 }
245
246 pub fn process_group_pairwise_payload(
247 &mut self,
248 payload: &[u8],
249 from_owner_pubkey: PublicKey,
250 from_sender_device_pubkey: Option<PublicKey>,
251 ) -> anyhow::Result<ProtocolGroupIncomingResult> {
252 self.process_group_pairwise_payload_inner(
253 payload,
254 from_owner_pubkey,
255 from_sender_device_pubkey,
256 true,
257 false,
258 )
259 }
260
261 pub fn process_local_sibling_group_pairwise_payload(
262 &mut self,
263 payload: &[u8],
264 from_owner_pubkey: PublicKey,
265 from_sender_device_pubkey: Option<PublicKey>,
266 ) -> anyhow::Result<ProtocolGroupIncomingResult> {
267 self.process_group_pairwise_payload_inner(
268 payload,
269 from_owner_pubkey,
270 from_sender_device_pubkey,
271 false,
272 true,
273 )
274 }
275
276 fn process_group_pairwise_payload_inner(
277 &mut self,
278 payload: &[u8],
279 from_owner_pubkey: PublicKey,
280 from_sender_device_pubkey: Option<PublicKey>,
281 forward_to_local_siblings: bool,
282 trust_local_sibling_attribution: bool,
283 ) -> anyhow::Result<ProtocolGroupIncomingResult> {
284 let (is_group_payload, is_supported_group_payload) =
285 classify_group_pairwise_payload(payload).unwrap_or((false, false));
286 if is_group_payload && !is_supported_group_payload {
287 return Ok(ProtocolGroupIncomingResult {
288 consumed: true,
289 ..Default::default()
290 });
291 }
292 let sender_device = from_sender_device_pubkey.map(ndr_device);
293 let sender_owner = ndr_owner(from_owner_pubkey);
294 if is_supported_group_payload && sender_device.is_none() && !trust_local_sibling_attribution
295 {
296 return Ok(ProtocolGroupIncomingResult {
300 consumed: true,
301 ..Default::default()
302 });
303 }
304 let sender_owner = if trust_local_sibling_attribution {
305 sender_owner
309 } else {
310 match self.resolve_group_pairwise_sender_owner(sender_owner, sender_device) {
311 ProtocolSenderOwnerResolution::Verified { owner }
312 | ProtocolSenderOwnerResolution::ProvisionalDeviceOwner { owner } => owner,
313 ProtocolSenderOwnerResolution::PendingOwnerClaim {
314 storage_owner,
315 claimed_owner: _,
316 sender_device,
317 } => {
318 if is_supported_group_payload {
319 self.queue_pending_group_pairwise_payload(
320 storage_owner,
321 Some(sender_device),
322 payload.to_vec(),
323 unix_now().get(),
324 )?;
325 return Ok(ProtocolGroupIncomingResult {
326 consumed: true,
327 ..Default::default()
328 });
329 }
330 storage_owner
331 }
332 }
333 };
334 let remote_sender_key_distribution_group_id =
335 if sender_owner != self.local_owner && sender_device.is_some() {
336 JsonGroupPayloadCodecV1
337 .decode_pairwise_command(payload)
338 .ok()
339 .flatten()
340 .and_then(|command| match command {
341 GroupPairwiseCommand::SenderKeyDistribution { distribution } => {
342 Some(distribution.group_id)
343 }
344 _ => None,
345 })
346 } else {
347 None
348 };
349 let previous_groups = is_supported_group_payload.then(|| self.group_manager.snapshot());
350 let result = match sender_device {
351 Some(device_pubkey) => {
352 self.group_manager
353 .handle_pairwise_payload(sender_owner, device_pubkey, payload)
354 }
355 None => self.group_manager.handle_incoming(sender_owner, payload),
356 };
357
358 let now = NdrUnixSeconds(unix_now().get());
359 match result {
360 Ok(Some(event)) => {
361 let group_changed = previous_groups
362 .as_ref()
363 .is_some_and(|previous| *previous != self.group_manager.snapshot());
364 if let GroupIncomingEvent::SenderKeyRepairRequested(repair) = event {
365 let effects = self.sender_key_repair_response_effects(
366 repair.requester_owner,
367 &repair.request,
368 NdrUnixSeconds(unix_now().get()),
369 )?;
370 self.persist()?;
371 return Ok(ProtocolGroupIncomingResult {
372 effects,
373 consumed: true,
374 ..Default::default()
375 });
376 }
377 let mut effects = Vec::new();
378 if group_changed && matches!(&event, GroupIncomingEvent::MetadataUpdated(_)) {
379 for pending in &mut self.pending_group_pairwise_payloads {
380 pending.next_retry_at_secs = 0;
381 }
382 }
383 if group_changed && forward_to_local_siblings && sender_owner != self.local_owner {
384 if let GroupIncomingEvent::MetadataUpdated(group) = &event {
385 let sync_effects = self.sync_group_to_local_siblings(group)?;
386 effects.extend(sync_effects);
387 }
388 if let (Some(group_id), Some(sender_device)) =
389 (&remote_sender_key_distribution_group_id, sender_device)
390 {
391 effects.extend(
392 self.sync_remote_group_sender_key_distribution_to_local_siblings(
393 group_id,
394 sender_owner,
395 sender_device,
396 payload,
397 )?,
398 );
399 }
400 }
401 let mut events = vec![event];
402 let retry = self.retry_pending_group_inputs(now)?;
403 events.extend(retry.events);
404 effects.extend(retry.effects);
405 let fanout_retry = self.retry_pending_group_fanouts(now)?;
406 effects.extend(fanout_retry.effects);
407 if group_changed || !effects.is_empty() {
408 self.persist()?;
409 }
410 Ok(ProtocolGroupIncomingResult {
411 events,
412 effects,
413 consumed: true,
414 ..Default::default()
415 })
416 }
417 Ok(None) => Ok(ProtocolGroupIncomingResult {
418 consumed: is_group_payload,
419 ..Default::default()
420 }),
421 Err(error) => {
422 if is_supported_group_payload {
423 self.queue_pending_group_pairwise_payload(
424 sender_owner,
425 sender_device,
426 payload.to_vec(),
427 unix_now().get(),
428 )?;
429 Ok(ProtocolGroupIncomingResult {
430 consumed: true,
431 ..Default::default()
432 })
433 } else {
434 Err(error.into())
435 }
436 }
437 }
438 }
439
440 pub fn pending_group_decrypted_delivery(
444 &self,
445 event_id: &str,
446 ) -> anyhow::Result<Option<GroupIncomingEvent>> {
447 if !event_id.starts_with("group-delivery:") {
448 return Ok(None);
449 }
450 let pending = self
451 .pending_decrypted_deliveries
452 .iter()
453 .find(|pending| pending.event_id.as_deref() == Some(event_id))
454 .ok_or_else(|| anyhow::anyhow!("group delivery is not in the authenticated journal"))?;
455 let Some(GroupPairwiseCommand::GroupMessage {
456 group_id,
457 revision,
458 body,
459 }) = JsonGroupPayloadCodecV1.decode_pairwise_command(pending.content.as_bytes())?
460 else {
461 anyhow::bail!("invalid group delivery journal envelope");
462 };
463 Ok(Some(GroupIncomingEvent::Message(
464 nostr_double_ratchet::GroupReceivedMessage {
465 group_id,
466 revision,
467 body,
468 sender_owner: ndr_owner(pending.sender),
469 sender_device: pending.sender_device.map(ndr_device),
470 },
471 )))
472 }
473
474 pub fn retry_pending_protocol(
475 &mut self,
476 now: NdrUnixSeconds,
477 ) -> anyhow::Result<ProtocolRetryBatch> {
478 {
479 #[cfg(all(test, target_os = "linux"))]
480 let _phase = tests::RetryPhaseTimer::start("retirement");
481 self.retire_ineligible_group_publications()?;
482 self.flush_discarded_direct_receives()?;
483 }
484 let group_result = {
485 #[cfg(all(test, target_os = "linux"))]
486 let _phase = tests::RetryPhaseTimer::start("group_inputs");
487 self.retry_pending_group_inputs(now)?
488 };
489 let group_fanout_result = {
490 #[cfg(all(test, target_os = "linux"))]
491 let _phase = tests::RetryPhaseTimer::start("group_fanouts");
492 self.retry_pending_group_fanouts(now)?
493 };
494 let mut group_result = group_result;
495 group_result.effects.extend(group_fanout_result.effects);
496 {
497 #[cfg(all(test, target_os = "linux"))]
498 let _phase = tests::RetryPhaseTimer::start("inbound");
499 self.retry_pending_inbound_direct_events(now)?;
500 }
501 let direct_messages = self
502 .pending_decrypted_deliveries
503 .iter()
504 .filter(|delivery| !delivery.discarded)
505 .cloned()
506 .map(ProtocolDecryptedMessage::from)
507 .collect::<Vec<_>>();
508 let mut effects = {
509 #[cfg(all(test, target_os = "linux"))]
510 let _phase = tests::RetryPhaseTimer::start("remote_sends");
511 self.retry_pending_remote_sends(now)?
512 };
513 {
514 #[cfg(all(test, target_os = "linux"))]
515 let _phase = tests::RetryPhaseTimer::start("local_siblings");
516 effects.extend(self.retry_pending_local_sibling_sends(now)?);
517 }
518 let offered = group_result
519 .effects
520 .iter()
521 .chain(&effects)
522 .map(|effect| {
523 let ProtocolEffect::Publish(publish) = effect;
524 publish.event.id
525 })
526 .collect::<HashSet<_>>();
527 effects.extend(
528 self.pending_group_publish_effects()
529 .into_iter()
530 .filter(|effect| {
531 let ProtocolEffect::Publish(publish) = effect;
532 !offered.contains(&publish.event.id)
533 }),
534 );
535 let batch = ProtocolRetryBatch {
536 group_result,
537 direct_messages,
538 effects,
539 };
540 if !batch.is_empty() {
541 self.subscription_generation = self.subscription_generation.wrapping_add(1);
542 }
543 Ok(batch)
544 }
545
546 pub(super) fn discard_pending_messages_for_other_devices(&mut self) -> anyhow::Result<()> {
547 let foreign_events = self
548 .pending_inbound
549 .iter()
550 .filter(|pending| self.message_targets_another_device(&pending.event))
551 .map(|pending| pending.event.clone())
552 .collect::<Vec<_>>();
553 if foreign_events.is_empty() {
554 return Ok(());
555 }
556 let ids = foreign_events
557 .iter()
558 .map(|event| event.id)
559 .collect::<HashSet<_>>();
560 self.with_state_checkpoint(|engine| {
561 engine.invalidate_pending_inbound_retry_deadline();
562 engine
563 .pending_inbound
564 .retain(|pending| !ids.contains(&pending.event.id));
565 for event in &foreign_events {
567 engine.clear_pending_group_sender_key_candidate_for_direct_event(event);
568 }
569 engine.persist()
570 })
571 }
572
573 pub fn ack_pending_decrypted_deliveries(&mut self) -> anyhow::Result<()> {
574 let ids = self
575 .pending_decrypted_deliveries
576 .iter()
577 .filter(|delivery| !delivery.discarded)
578 .filter_map(|delivery| delivery.event_id.clone())
579 .collect();
580 self.ack_decrypted_delivery_ids(&ids)
581 }
582
583 pub fn ack_decrypted_delivery_ids(
586 &mut self,
587 event_ids: &HashSet<String>,
588 ) -> anyhow::Result<()> {
589 if !self.pending_decrypted_deliveries.iter().any(|delivery| {
590 delivery
591 .event_id
592 .as_ref()
593 .is_some_and(|id| event_ids.contains(id))
594 }) {
595 return Ok(());
596 }
597 let before = self.pending_decrypted_deliveries.clone();
598 self.pending_decrypted_deliveries.retain(|delivery| {
599 delivery.discarded
600 || !delivery
601 .event_id
602 .as_ref()
603 .is_some_and(|id| event_ids.contains(id))
604 });
605 if let Err(error) = self.persist() {
606 self.pending_decrypted_deliveries = before;
607 return Err(error);
608 }
609 Ok(())
610 }
611
612 pub(super) fn retry_pending_inbound_direct_events_inner(
613 &mut self,
614 now: NdrUnixSeconds,
615 fingerprints: &mut InboundReceiveFingerprints,
616 ) -> anyhow::Result<Vec<ProtocolDecryptedMessage>> {
617 self.invalidate_pending_inbound_retry_deadline();
621 let pending = self
626 .pending_inbound
627 .iter()
628 .enumerate()
629 .filter(|(_, pending)| {
630 #[cfg(test)]
631 tests::record_inbound_retry_deadline_scan();
632 pending.next_retry_at_secs <= now.get()
633 })
634 .map(|(index, pending)| (index, pending.clone()))
635 .collect::<Vec<_>>();
636 let mut messages = Vec::new();
637 for (original_index, pending) in pending {
638 match self.decrypt_pending_direct_message_with_cache(&pending, fingerprints) {
639 Ok(DirectReceive::Message(message)) => {
640 self.pending_inbound
641 .retain(|item| item.event.id != pending.event.id);
642 messages.push(message);
643 }
644 Ok(DirectReceive::Discarded) => {
645 self.pending_inbound
646 .retain(|item| item.event.id != pending.event.id);
647 }
648 Err(error) if error.downcast_ref::<StorageError>().is_some() => {
649 return Err(error);
652 }
653 Ok(DirectReceive::Pending) | Err(_) => {
654 let matches_id = |item: &ProtocolPendingInbound| {
662 #[cfg(test)]
663 tests::record_inbound_retry_lookup();
664 item.event.id == pending.event.id
665 };
666 let index = if self
667 .pending_inbound
668 .get(original_index)
669 .is_some_and(matches_id)
670 {
671 Some(original_index)
672 } else {
673 self.pending_inbound.iter().position(matches_id)
674 };
675 if let Some(index) = index {
676 self.pending_inbound[index].next_retry_at_secs =
677 next_pending_retry_at_secs(pending.created_at_secs, now);
678 }
679 }
680 }
681 }
682 self.refresh_pending_inbound_retry_deadline();
683 Ok(messages)
684 }
685
686 #[cfg(test)]
687 pub(super) fn decrypt_pending_direct_message_event(
688 &mut self,
689 pending: &ProtocolPendingInbound,
690 ) -> anyhow::Result<DirectReceive> {
691 if let Some(envelope) = pending.envelope.as_ref() {
692 return self.decrypt_direct_message_envelope(&pending.event, envelope, true);
693 }
694 self.decrypt_direct_message_event(&pending.event)
695 }
696
697 #[cfg(test)]
698 fn decrypt_direct_message_event(&mut self, event: &Event) -> anyhow::Result<DirectReceive> {
699 let envelope = parse_message_event(event)?;
700 self.decrypt_direct_message_envelope(event, &envelope, true)
701 }
702
703 fn decrypt_direct_message_envelope(
704 &mut self,
705 event: &Event,
706 envelope: &MessageEnvelope,
707 record_delivery: bool,
708 ) -> anyhow::Result<DirectReceive> {
709 self.decrypt_direct_message_envelope_with_cache(event, envelope, record_delivery, None)
710 }
711
712 pub(super) fn decrypt_direct_message_envelope_with_cache(
713 &mut self,
714 event: &Event,
715 envelope: &MessageEnvelope,
716 record_delivery: bool,
717 fingerprints: Option<&mut InboundReceiveFingerprints>,
718 ) -> anyhow::Result<DirectReceive> {
719 if let Some(delivery) = self
720 .pending_decrypted_deliveries
721 .iter()
722 .find(|delivery| delivery.event_id.as_deref() == Some(event.id.to_hex().as_str()))
723 .cloned()
724 {
725 if delivery.discarded {
727 self.flush_discarded_direct_receives()?;
728 return Ok(DirectReceive::Discarded);
729 }
730 self.persist()?;
731 return Ok(DirectReceive::Message(delivery.into()));
732 }
733 let sender_owner = match self.resolve_message_sender_owner(envelope) {
734 ProtocolSenderOwnerResolution::Verified { owner }
735 | ProtocolSenderOwnerResolution::ProvisionalDeviceOwner { owner } => owner,
736 ProtocolSenderOwnerResolution::PendingOwnerClaim { .. } => {
737 return Ok(DirectReceive::Pending);
738 }
739 };
740 let Some(received) =
741 self.receive_direct_message_with_cache(event, envelope, sender_owner, fingerprints)?
742 else {
743 return Ok(DirectReceive::Pending);
744 };
745 self.clear_pending_group_sender_key_candidate_for_direct_event(event);
746 self.invalidate_known_message_author_cache();
747 let from_local_sibling = received.owner_pubkey == self.local_owner;
748 let local_sibling = from_local_sibling
749 .then(|| decode_local_sibling_payload(&received.payload))
750 .flatten();
751 let (conversation_owner, sender, sender_device, payload) = match local_sibling {
752 Some((owner, original_device, payload)) => (
753 Some(owner),
754 original_device.map_or(self.owner_pubkey, |_| owner),
755 original_device.or(Some(public_device(received.device_pubkey)?)),
756 payload,
757 ),
758 _ => (
759 None,
760 public_owner(received.owner_pubkey)?,
761 Some(public_device(received.device_pubkey)?),
762 received.payload,
763 ),
764 };
765 if from_local_sibling && is_message_mutation_payload(&payload) {
768 self.pending_decrypted_deliveries
769 .push(ProtocolPendingDecryptedDelivery {
770 discarded: true,
771 sender,
772 sender_device,
773 conversation_owner,
774 content: String::new(),
775 event_id: Some(event.id.to_string()),
776 created_at_secs: event.created_at.as_secs(),
777 });
778 self.invalidate_pending_inbound_retry_deadline();
779 self.pending_inbound
780 .retain(|pending| pending.event.id != event.id);
781 self.flush_discarded_direct_receives()?;
782 return Ok(DirectReceive::Discarded);
783 }
784 let content = String::from_utf8(payload)?;
785 let decrypted = ProtocolDecryptedMessage {
786 created_at_secs: event.created_at.as_secs(),
787 sender,
788 sender_device,
789 conversation_owner,
790 content,
791 event_id: Some(event.id.to_string()),
792 };
793 if record_delivery {
794 self.record_pending_decrypted_delivery(decrypted.clone(), event.created_at.as_secs());
795 }
796 self.persist()?;
797 Ok(DirectReceive::Message(decrypted))
798 }
799
800 fn retry_pending_group_inputs(
801 &mut self,
802 now: NdrUnixSeconds,
803 ) -> anyhow::Result<ProtocolGroupIncomingResult> {
804 let mut result = ProtocolGroupIncomingResult {
805 consumed: false,
806 ..Default::default()
807 };
808
809 let pairwise = std::mem::take(&mut self.pending_group_pairwise_payloads);
810 let mut still_pairwise = Vec::new();
811 let mut persist_needed = false;
812 for mut pending in pairwise {
813 if pending.next_retry_at_secs > now.get() {
814 still_pairwise.push(pending);
815 continue;
816 }
817 let (_, is_supported_group_payload) =
818 classify_group_pairwise_payload(&pending.payload).unwrap_or((false, false));
819 if !is_supported_group_payload {
820 persist_needed = true;
821 continue;
822 }
823 if pending.sender_device.is_none() {
824 persist_needed = true;
827 continue;
828 }
829 let sender_resolution = self
830 .resolve_group_pairwise_sender_owner(pending.sender_owner, pending.sender_device);
831 let sender_owner = match sender_resolution {
832 ProtocolSenderOwnerResolution::Verified { owner }
833 | ProtocolSenderOwnerResolution::ProvisionalDeviceOwner { owner } => owner,
834 ProtocolSenderOwnerResolution::PendingOwnerClaim { .. } => {
835 pending.next_retry_at_secs =
836 next_pending_retry_at_secs(pending.created_at_secs, now);
837 still_pairwise.push(pending);
838 continue;
839 }
840 };
841 let outcome = match pending.sender_device {
842 Some(device_pubkey) => self.group_manager.handle_pairwise_payload(
843 sender_owner,
844 device_pubkey,
845 &pending.payload,
846 ),
847 None => self
848 .group_manager
849 .handle_incoming(sender_owner, &pending.payload),
850 };
851 match outcome {
852 Ok(Some(event)) => {
853 if let GroupIncomingEvent::SenderKeyRepairRequested(repair) = event {
854 let effects = self.sender_key_repair_response_effects(
855 repair.requester_owner,
856 &repair.request,
857 now,
858 )?;
859 result.effects.extend(effects);
860 } else {
861 result.events.push(event);
862 }
863 persist_needed = true;
864 }
865 Ok(None) => {
866 persist_needed = true;
867 }
868 Err(_) => {
869 pending.next_retry_at_secs =
870 next_pending_retry_at_secs(pending.created_at_secs, now);
871 still_pairwise.push(pending);
872 }
873 }
874 }
875 self.pending_group_pairwise_payloads = still_pairwise;
876
877 let sender_keys = self.retry_eligible_group_sender_key_messages()?;
878 result.events.extend(sender_keys.events);
879 result.effects.extend(sender_keys.effects);
880 let repair_effects = self.retry_pending_group_sender_key_repairs(now)?;
881 if !repair_effects.is_empty() {
882 result.effects.extend(repair_effects);
883 persist_needed = true;
884 }
885 if persist_needed {
886 self.persist()?;
887 }
888 Ok(result)
889 }
890}