1use super::*;
2
3impl ProtocolEngine {
4 pub fn group_id_for_sender_event_author(&self, author: PublicKey) -> Option<String> {
6 self.group_manager
7 .group_id_for_sender_event_pubkey(ndr_device(author))
8 }
9
10 pub fn has_pending_group_pairwise_payloads(&self) -> bool {
11 !self.pending_group_pairwise_payloads.is_empty()
12 }
13
14 pub fn missing_group_metadata_sources(&self) -> Vec<(PublicKey, String, PublicKey)> {
17 let pending = &self.pending_group_pairwise_payloads;
18 if pending.is_empty() {
19 return Vec::new();
20 }
21 let start = ((unix_now().get() / 60) as usize % pending.len().div_ceil(32)) * 32;
22 pending
23 .iter()
24 .skip(start)
25 .take(32)
26 .filter_map(|pending| {
27 let owner = match self.resolve_group_pairwise_sender_owner(
28 pending.sender_owner,
29 pending.sender_device,
30 ) {
31 ProtocolSenderOwnerResolution::Verified { owner } => owner,
32 _ => return None,
33 };
34 let GroupPairwiseCommand::SenderKeyDistribution { distribution } =
35 JsonGroupPayloadCodecV1
36 .decode_pairwise_command(&pending.payload)
37 .ok()??
38 else {
39 return None;
40 };
41 if self.group_manager.group(&distribution.group_id).is_some() {
42 return None;
43 }
44 Some((
45 public_owner(owner).ok()?,
46 distribution.group_id,
47 public_device(distribution.sender_event_pubkey).ok()?,
48 ))
49 })
50 .collect()
51 }
52
53 pub fn resend_private_group_context(
56 &mut self,
57 group_id: &str,
58 requester: PublicKey,
59 author: Option<PublicKey>,
60 ) -> anyhow::Result<Vec<ProtocolEffect>> {
61 let Some(group) = self.group_manager.group(group_id) else {
62 return Ok(Vec::new());
63 };
64 if !group.members.contains(&self.local_owner)
65 || !group.members.contains(&ndr_owner(requester))
66 {
67 return Ok(Vec::new());
68 }
69 self.with_state_checkpoint(|engine| {
70 let effects = engine.sender_key_repair_response_effects(
71 ndr_owner(requester),
72 &SenderKeyRepairRequest {
73 group_id: group.group_id,
74 sender_event_pubkey: author.map(ndr_device).unwrap_or(engine.local_device),
75 key_id: None,
76 message_number: None,
77 required_revision: Some(group.revision),
78 created_at: NdrUnixSeconds(unix_now().get()),
79 },
80 NdrUnixSeconds(unix_now().get()),
81 )?;
82 engine.retain_group_publications(&effects, Some(ndr_owner(requester)))?;
83 engine.persist()?;
84 Ok(effects)
85 })
86 }
87 pub(super) fn queue_pending_group_sender_key_message(
88 &mut self,
89 parsed: nostr_double_ratchet::wire::ParsedGroupSenderKeyMessageEvent,
90 ) -> anyhow::Result<()> {
91 self.queue_group_sender_key_candidate(parsed, true)
92 }
93
94 pub(super) fn queue_group_sender_key_candidate(
95 &mut self,
96 parsed: nostr_double_ratchet::wire::ParsedGroupSenderKeyMessageEvent,
97 fresh: bool,
98 ) -> anyhow::Result<()> {
99 if self.unmapped_group_sender_key_candidate_is_known_message_author(&parsed) {
100 return Ok(());
101 }
102
103 if self
104 .group_sender_key_message_from_parsed(&parsed)
105 .is_some_and(|message| {
106 self.processed_group_sender_key_messages
107 .contains(&group_sender_key_fingerprint(&message))
108 })
109 {
110 return Ok(());
111 }
112
113 if let Some(group_id) = self.inactive_local_group_id_for_sender_key_candidate(&parsed) {
114 if self.clear_group_sender_key_repairs(
115 &group_id,
116 parsed.sender_event_pubkey,
117 parsed.encrypted_header.is_none().then_some(parsed.key_id),
118 parsed
119 .encrypted_header
120 .is_none()
121 .then_some(parsed.message_number),
122 ) {
123 self.persist()?;
124 }
125 return Ok(());
126 }
127
128 if !self.pending_group_sender_key_messages.contains(&parsed) {
129 if fresh {
130 self.admit_fresh_group_sender_key_candidate(
131 &parsed,
132 self.pending_group_sender_key_messages.len(),
133 );
134 }
135 if let Some(message) = self.group_sender_key_message_from_parsed(&parsed) {
139 let fingerprint = group_sender_key_fingerprint(&message);
140 let mut retry = self.group_sender_key_retry.borrow_mut();
141 if let Some(fresh) = retry
142 .fresh
143 .iter_mut()
144 .find(|fresh| fresh.fingerprint == fingerprint)
145 {
146 fresh.pending_index = self.pending_group_sender_key_messages.len();
147 }
148 if retry.queued.insert(fingerprint.clone()) {
149 retry
150 .ready
151 .push_back((parsed.sender_event_pubkey, fingerprint));
152 }
153 }
154 self.pending_group_sender_key_messages.push(parsed);
155 self.persist()?;
156 }
157 Ok(())
158 }
159
160 pub(super) fn clear_pending_group_sender_key_candidate_for_direct_event(
161 &mut self,
162 event: &Event,
163 ) {
164 if !protocol_event_has_tag(event, "header") {
165 return;
166 }
167 let Ok(parsed) = parse_group_sender_key_message_event_unchecked(event) else {
168 return;
169 };
170 self.clear_pending_group_sender_key_candidate(&parsed);
171 }
172
173 pub(super) fn clear_pending_group_sender_key_candidate(
174 &mut self,
175 parsed: &nostr_double_ratchet::wire::ParsedGroupSenderKeyMessageEvent,
176 ) -> bool {
177 {
178 let mut retry = self.group_sender_key_retry.borrow_mut();
179 retry.fresh.retain(|fresh| fresh.parsed.as_ref() != parsed);
180 if retry
181 .active
182 .as_ref()
183 .is_some_and(|active| active.matches(parsed))
184 {
185 retry.active = None;
186 }
187 }
188 let original_len = self.pending_group_sender_key_messages.len();
189 self.pending_group_sender_key_messages
190 .retain(|pending| pending != parsed);
191 if self.pending_group_sender_key_messages.len() == original_len {
192 return false;
193 }
194
195 let Some(group_id) = self
196 .group_manager
197 .group_id_for_sender_event_pubkey(parsed.sender_event_pubkey)
198 else {
199 return true;
200 };
201 if !self.has_pending_group_sender_key_candidate(&group_id, parsed.sender_event_pubkey) {
202 self.clear_group_sender_key_repairs(
203 &group_id,
204 parsed.sender_event_pubkey,
205 parsed.encrypted_header.is_none().then_some(parsed.key_id),
206 parsed
207 .encrypted_header
208 .is_none()
209 .then_some(parsed.message_number),
210 );
211 }
212 true
213 }
214
215 fn has_pending_group_sender_key_candidate(
216 &self,
217 group_id: &str,
218 sender_event_pubkey: NdrDevicePubkey,
219 ) -> bool {
220 self.pending_group_sender_key_messages
221 .iter()
222 .any(|pending| {
223 pending.sender_event_pubkey == sender_event_pubkey
224 && self
225 .group_manager
226 .group_id_for_sender_event_pubkey(pending.sender_event_pubkey)
227 .as_deref()
228 == Some(group_id)
229 })
230 }
231
232 pub(super) fn unmapped_group_sender_key_candidate_is_known_message_author(
233 &self,
234 parsed: &nostr_double_ratchet::wire::ParsedGroupSenderKeyMessageEvent,
235 ) -> bool {
236 if self
237 .group_manager
238 .group_id_for_sender_event_pubkey(parsed.sender_event_pubkey)
239 .is_some()
240 {
241 return false;
242 }
243
244 public_device(parsed.sender_event_pubkey)
245 .is_ok_and(|author| self.is_known_message_author(author))
246 }
247
248 fn inactive_local_group_id_for_sender_key_candidate(
249 &self,
250 parsed: &nostr_double_ratchet::wire::ParsedGroupSenderKeyMessageEvent,
251 ) -> Option<String> {
252 let group_id = self
253 .group_manager
254 .group_id_for_sender_event_pubkey(parsed.sender_event_pubkey)?;
255 self.local_owner_is_inactive_for_group(&group_id)
256 .then_some(group_id)
257 }
258
259 pub(super) fn local_owner_is_inactive_for_group(&self, group_id: &str) -> bool {
260 self.group_manager
261 .group_has_member(group_id, self.local_owner)
262 == Some(false)
263 }
264
265 fn inactive_local_group_ids(&self) -> HashSet<String> {
266 self.group_manager
267 .snapshot()
268 .groups
269 .into_iter()
270 .filter(|group| !group.members.contains(&self.local_owner))
271 .map(|group| group.group_id)
272 .collect()
273 }
274
275 pub(super) fn prune_pending_group_sender_key_work_for_inactive_local_groups(&mut self) -> bool {
276 let inactive_group_ids = self.inactive_local_group_ids();
277 if inactive_group_ids.is_empty() {
278 return false;
279 }
280 let inactive_sender_event_pubkeys = self
281 .group_manager
282 .snapshot()
283 .sender_keys
284 .into_iter()
285 .filter(|record| inactive_group_ids.contains(&record.group_id))
286 .map(|record| record.sender_event_pubkey)
287 .collect::<HashSet<_>>();
288
289 let original_message_len = self.pending_group_sender_key_messages.len();
290 self.pending_group_sender_key_messages.retain(|pending| {
291 !inactive_sender_event_pubkeys.contains(&pending.sender_event_pubkey)
292 });
293
294 let original_repair_len = self.pending_group_sender_key_repairs.len();
295 self.pending_group_sender_key_repairs
296 .retain(|pending| !inactive_group_ids.contains(&pending.group_id));
297
298 self.pending_group_sender_key_messages.len() != original_message_len
299 || self.pending_group_sender_key_repairs.len() != original_repair_len
300 }
301
302 pub(super) fn group_sender_key_message_from_parsed(
303 &self,
304 parsed: &nostr_double_ratchet::wire::ParsedGroupSenderKeyMessageEvent,
305 ) -> Option<GroupSenderKeyMessage> {
306 let group_id = self
307 .group_manager
308 .group_id_for_sender_event_pubkey(parsed.sender_event_pubkey)?;
309 Some(GroupSenderKeyMessage {
310 group_id,
311 sender_event_pubkey: parsed.sender_event_pubkey,
312 key_id: parsed.key_id,
313 message_number: parsed.message_number,
314 encrypted_header: parsed.encrypted_header.clone(),
315 created_at: parsed.created_at,
316 ciphertext: parsed.ciphertext.clone(),
317 })
318 }
319
320 pub(super) fn group_sender_key_message_has_pending_repair(
321 &self,
322 message: &GroupSenderKeyMessage,
323 ) -> bool {
324 let sender = message.sender_event_pubkey.to_hex();
325 let key_id = message.encrypted_header.is_none().then_some(message.key_id);
326 let number = message
327 .encrypted_header
328 .is_none()
329 .then_some(message.message_number);
330 self.pending_group_sender_key_repairs.iter().any(|pending| {
331 pending.group_id == message.group_id
332 && pending.sender_event_pubkey_hex == sender
333 && (message.encrypted_header.is_some()
334 || (pending.key_id == key_id && pending.message_number == number))
335 })
336 }
337
338 pub(super) fn handle_group_sender_key_message(
339 &mut self,
340 message: GroupSenderKeyMessage,
341 ) -> anyhow::Result<ProtocolGroupIncomingResult> {
342 let fingerprint = group_sender_key_fingerprint(&message);
343 if self.local_owner_is_inactive_for_group(&message.group_id) {
344 let mut retry = self.group_sender_key_retry.borrow_mut();
345 if retry
346 .active
347 .as_ref()
348 .is_some_and(|active| active.fingerprint == fingerprint)
349 {
350 retry.active = None;
351 }
352 retry.prepared = None;
353 return Ok(ProtocolGroupIncomingResult {
354 consumed: true,
355 ..Default::default()
356 });
357 }
358 if self
359 .processed_group_sender_key_messages
360 .contains(&fingerprint)
361 {
362 return Ok(ProtocolGroupIncomingResult {
363 consumed: true,
364 ..Default::default()
365 });
366 }
367 if self.group_manager.is_local_sender_key_stream(
371 &message.group_id,
372 message.sender_event_pubkey,
373 self.local_device,
374 ) {
375 if self.clear_group_sender_key_repairs(
376 &message.group_id,
377 message.sender_event_pubkey,
378 None,
379 None,
380 ) {
381 self.persist()?;
382 }
383 return Ok(ProtocolGroupIncomingResult {
384 consumed: true,
385 ..Default::default()
386 });
387 }
388 let plan = match self.prepare_group_sender_key_message(&message, &fingerprint) {
391 Ok(Some(plan)) => Ok(plan),
392 Ok(None) => {
393 return Ok(ProtocolGroupIncomingResult {
394 consumed: true,
395 pending: true,
396 ..Default::default()
397 })
398 }
399 Err(error @ nostr_double_ratchet::Error::Decryption(_))
400 if matches!(&error, nostr_double_ratchet::Error::Decryption(reason)
401 if reason == "duplicate or missing sender-key message") =>
402 {
403 Err(error)
404 }
405 Err(error) => return Err(error.into()),
406 };
407 if self.batch_depth.get() > 0 {
408 return self.apply_group_sender_key_message(message, fingerprint, plan);
409 }
410 #[cfg(test)]
413 {
414 self.group_sender_key_retry.borrow_mut().receive_checkpoints += 1;
415 }
416 let checkpoint = (
417 self.group_manager.clone(),
418 self.session_manager.clone(),
419 self.pending_group_sender_key_repairs.clone(),
420 self.pending_group_fanouts.clone(),
421 self.processed_group_sender_key_messages.clone(),
422 self.pending_decrypted_deliveries.clone(),
423 self.batch_persist_dirty.get(),
424 );
425 let result = self.apply_group_sender_key_message(message, fingerprint, plan);
426 if result.is_err() {
427 self.group_manager = checkpoint.0;
428 self.session_manager = checkpoint.1;
429 self.pending_group_sender_key_repairs = checkpoint.2;
430 self.invalidate_pending_group_fanout_retry_deadline();
431 self.pending_group_fanouts = checkpoint.3;
432 self.processed_group_sender_key_messages = checkpoint.4;
433 self.pending_decrypted_deliveries = checkpoint.5;
434 self.batch_persist_dirty.set(checkpoint.6);
435 self.invalidate_known_message_author_cache();
436 }
437 result
438 }
439
440 fn apply_group_sender_key_message(
441 &mut self,
442 message: GroupSenderKeyMessage,
443 fingerprint: String,
444 plan: nostr_double_ratchet::Result<nostr_double_ratchet::GroupSenderKeyReceivePlan>,
445 ) -> anyhow::Result<ProtocolGroupIncomingResult> {
446 let message_repair_group_id = message.group_id.clone();
447 let message_repair_sender = message.sender_event_pubkey;
448 let message_repair_key_id = message.encrypted_header.is_none().then_some(message.key_id);
449 let message_repair_number = message
450 .encrypted_header
451 .is_none()
452 .then_some(message.message_number);
453 let result =
454 match plan.and_then(|plan| self.group_manager.apply_sender_key_receive_plan(plan)) {
455 Ok(result) => result,
456 Err(nostr_double_ratchet::Error::Decryption(error))
457 if error == "duplicate or missing sender-key message" =>
458 {
459 self.clear_group_sender_key_repairs(
460 &message_repair_group_id,
461 message_repair_sender,
462 message_repair_key_id,
463 message_repair_number,
464 );
465 self.processed_group_sender_key_messages.insert(fingerprint);
466 self.persist()?;
467 return Ok(ProtocolGroupIncomingResult {
468 consumed: true,
469 ..Default::default()
470 });
471 }
472 Err(error) => return Err(error.into()),
473 };
474 let now = NdrUnixSeconds(unix_now().get());
475 let repair_request =
476 SenderKeyRepairRequest::from_pending_sender_key_message(&message, &result, now);
477 match result {
478 GroupSenderKeyHandleResult::Event(event) => {
479 let discard = matches!(&event, GroupIncomingEvent::Message(received)
480 if received.sender_owner == self.local_owner
481 && is_message_mutation_payload(&received.body));
482 if let GroupIncomingEvent::Message(received) = &event {
483 if !discard {
484 let payload = JsonGroupPayloadCodecV1.encode_pairwise_command(
487 nostr_double_ratchet::GroupPayloadEncodeContext {
488 local_device_pubkey: received
489 .sender_device
490 .unwrap_or(self.local_device),
491 created_at: message.created_at,
492 },
493 &GroupPairwiseCommand::GroupMessage {
494 group_id: received.group_id.clone(),
495 revision: received.revision,
496 body: received.body.clone(),
497 },
498 )?;
499 self.record_pending_decrypted_delivery(
500 ProtocolDecryptedMessage {
501 sender: public_owner(received.sender_owner)?,
502 sender_device: received
503 .sender_device
504 .map(public_device)
505 .transpose()?,
506 conversation_owner: None,
507 content: String::from_utf8(payload)?,
508 event_id: Some(format!("group-delivery:{fingerprint}")),
509 created_at_secs: message.created_at.get(),
510 },
511 message.created_at.get(),
512 );
513 }
514 }
515 self.clear_group_sender_key_repairs(
516 &message_repair_group_id,
517 message_repair_sender,
518 message_repair_key_id,
519 message_repair_number,
520 );
521 self.processed_group_sender_key_messages.insert(fingerprint);
522 self.persist()?;
523 Ok(ProtocolGroupIncomingResult {
524 events: if discard { Vec::new() } else { vec![event] },
525 consumed: true,
526 ..Default::default()
527 })
528 }
529 GroupSenderKeyHandleResult::PendingDistribution { .. }
530 | GroupSenderKeyHandleResult::PendingRevision { .. } => {
531 let Some(request) = repair_request else {
532 anyhow::bail!("pending sender-key result did not produce a repair request");
533 };
534 let effects = self.sender_key_repair_request_effects(request, now)?;
535 Ok(ProtocolGroupIncomingResult {
536 consumed: true,
537 pending: true,
538 effects,
539 ..Default::default()
540 })
541 }
542 GroupSenderKeyHandleResult::Ignored => {
543 self.processed_group_sender_key_messages.insert(fingerprint);
544 self.clear_group_sender_key_repairs(
545 &message_repair_group_id,
546 message_repair_sender,
547 message_repair_key_id,
548 message_repair_number,
549 );
550 self.persist()?;
551 Ok(ProtocolGroupIncomingResult {
552 consumed: true,
553 ..Default::default()
554 })
555 }
556 }
557 }
558
559 pub(super) fn sender_key_repair_request_effects(
560 &mut self,
561 request: SenderKeyRepairRequest,
562 now: NdrUnixSeconds,
563 ) -> anyhow::Result<Vec<ProtocolEffect>> {
564 if self.local_owner_is_inactive_for_group(&request.group_id) {
565 if self.clear_group_sender_key_repairs(
566 &request.group_id,
567 request.sender_event_pubkey,
568 request.key_id,
569 request.message_number,
570 ) {
571 self.persist()?;
572 }
573 return Ok(Vec::new());
574 }
575
576 let sender_event_pubkey_hex = request.sender_event_pubkey.to_hex();
577 let position = self
578 .pending_group_sender_key_repairs
579 .iter()
580 .position(|pending| {
581 pending.group_id == request.group_id
582 && pending.sender_event_pubkey_hex == sender_event_pubkey_hex
583 && pending.key_id == request.key_id
584 && pending.message_number == request.message_number
585 && pending.required_revision == request.required_revision
586 });
587 let index = if let Some(index) = position {
588 index
589 } else {
590 self.pending_group_sender_key_repairs
591 .push(ProtocolPendingGroupSenderKeyRepair {
592 group_id: request.group_id.clone(),
593 sender_event_pubkey_hex,
594 key_id: request.key_id,
595 message_number: request.message_number,
596 required_revision: request.required_revision,
597 created_at_secs: now.get(),
598 last_requested_at_secs: 0,
599 request_count: 0,
600 next_retry_at_secs: 0,
601 });
602 self.pending_group_sender_key_repairs.len() - 1
603 };
604 let Some(pending_repair) = self.pending_group_sender_key_repairs.get(index) else {
605 anyhow::bail!("pending sender-key repair index disappeared");
606 };
607 if Self::pending_group_sender_key_repair_due_at_secs(pending_repair) > now.get() {
608 return Ok(Vec::new());
609 }
610
611 let mut rng = OsRng;
612 let mut ctx = ProtocolContext::new(now, &mut rng);
613 let prepared = self.group_manager.request_sender_key_repair(
614 &mut self.session_manager,
615 &mut ctx,
616 &request,
617 )?;
618 let session_progress =
619 [&prepared.remote, &prepared.local_sibling]
620 .into_iter()
621 .any(|part| {
622 !part.deliveries.is_empty()
623 || !part.invite_responses.is_empty()
624 || !part.sender_key_messages.is_empty()
625 });
626 let local_sibling_state_may_change = !prepared.local_sibling.relay_gaps.is_empty()
629 || !prepared.local_sibling.pending_fanouts.is_empty();
630 let (output, fanouts_changed) =
631 self.protocol_group_send_from_prepared_with_progress(&prepared, None)?;
632 if let Some(pending) = self.pending_group_sender_key_repairs.get_mut(index) {
633 pending.last_requested_at_secs = now.get();
634 pending.request_count = pending.request_count.saturating_add(1);
635 pending.next_retry_at_secs =
636 protocol_sender_key_repair_next_retry_at(now, pending.request_count).get();
637 }
638 if session_progress || fanouts_changed || local_sibling_state_may_change {
639 self.persist()?;
642 }
643 self.invalidate_known_message_author_cache();
644 Ok(output.effects)
645 }
646
647 pub(super) fn retry_pending_group_sender_key_repairs(
648 &mut self,
649 now: NdrUnixSeconds,
650 ) -> anyhow::Result<Vec<ProtocolEffect>> {
651 let requests = self
652 .pending_group_sender_key_repairs
653 .iter()
654 .filter(|pending| {
655 Self::pending_group_sender_key_repair_due_at_secs(pending) <= now.get()
656 })
657 .filter_map(|pending| {
658 let sender = PublicKey::parse(&pending.sender_event_pubkey_hex).ok()?;
659 Some(SenderKeyRepairRequest {
660 group_id: pending.group_id.clone(),
661 sender_event_pubkey: ndr_device(sender),
662 key_id: pending.key_id,
663 message_number: pending.message_number,
664 required_revision: pending.required_revision,
665 created_at: NdrUnixSeconds(pending.created_at_secs),
666 })
667 })
668 .collect::<Vec<_>>();
669 let mut effects = Vec::new();
670 for request in requests {
671 let repair_effects = self.sender_key_repair_request_effects(request, now)?;
672 effects.extend(repair_effects);
673 }
674 Ok(effects)
675 }
676
677 pub(super) fn pending_group_sender_key_repair_due_at_secs(
678 pending: &ProtocolPendingGroupSenderKeyRepair,
679 ) -> u64 {
680 if pending.request_count == 0 || pending.last_requested_at_secs == 0 {
681 return pending.next_retry_at_secs;
682 }
683 let capped_due_at = pending.last_requested_at_secs.saturating_add(
684 protocol_sender_key_repair_retry_delay_secs(pending.request_count),
685 );
686 if pending.next_retry_at_secs == 0 {
687 capped_due_at
688 } else {
689 pending.next_retry_at_secs.min(capped_due_at)
690 }
691 }
692
693 pub(super) fn sender_key_repair_response_effects(
694 &mut self,
695 requester_owner: NdrOwnerPubkey,
696 request: &SenderKeyRepairRequest,
697 now: NdrUnixSeconds,
698 ) -> anyhow::Result<Vec<ProtocolEffect>> {
699 if self.group_sender_key_repair_response_throttled(requester_owner, request, now) {
700 return Ok(Vec::new());
701 }
702 let mut rng = OsRng;
703 let mut ctx = ProtocolContext::new(now, &mut rng);
704 let prepared = self.group_manager.respond_to_sender_key_repair_request(
705 &mut self.session_manager,
706 &mut ctx,
707 requester_owner,
708 request,
709 )?;
710 let response_deferred = !prepared.remote.pending_fanouts.is_empty()
711 || !prepared.local_sibling.pending_fanouts.is_empty();
712 let output = self.protocol_group_send_from_prepared(&prepared, None)?;
713 if !output.effects.is_empty() || response_deferred {
714 self.remember_group_sender_key_repair_response(requester_owner, request, now);
715 }
716 self.invalidate_known_message_author_cache();
717 Ok(output.effects)
718 }
719
720 pub(super) fn group_sender_key_repair_response_throttled(
721 &self,
722 requester_owner: NdrOwnerPubkey,
723 request: &SenderKeyRepairRequest,
724 now: NdrUnixSeconds,
725 ) -> bool {
726 let requester_owner_hex = requester_owner.to_hex();
727 let sender_event_pubkey_hex = request.sender_event_pubkey.to_hex();
728 self.answered_group_sender_key_repairs
731 .iter()
732 .any(|answered| {
733 answered.requester_owner_hex == requester_owner_hex
734 && answered.group_id == request.group_id.as_str()
735 && answered.sender_event_pubkey_hex == sender_event_pubkey_hex
736 && answered.key_id == request.key_id
737 && answered.message_number == request.message_number
738 && answered.required_revision == request.required_revision
739 && answered.next_response_at_secs > now.get()
740 })
741 }
742
743 fn remember_group_sender_key_repair_response(
744 &mut self,
745 requester_owner: NdrOwnerPubkey,
746 request: &SenderKeyRepairRequest,
747 now: NdrUnixSeconds,
748 ) {
749 let requester_owner_hex = requester_owner.to_hex();
750 let sender_event_pubkey_hex = request.sender_event_pubkey.to_hex();
751 let position = self
752 .answered_group_sender_key_repairs
753 .iter()
754 .position(|answered| {
755 answered.requester_owner_hex == requester_owner_hex
756 && answered.group_id == request.group_id.as_str()
757 && answered.sender_event_pubkey_hex == sender_event_pubkey_hex
758 && answered.key_id == request.key_id
759 && answered.message_number == request.message_number
760 && answered.required_revision == request.required_revision
761 });
762 let response_count = position
763 .and_then(|index| {
764 self.answered_group_sender_key_repairs
765 .get(index)
766 .map(|answered| answered.response_count.saturating_add(1))
767 })
768 .unwrap_or(1);
769 let next_response_at_secs =
770 protocol_sender_key_repair_next_retry_at(now, response_count).get();
771 if let Some(index) = position {
772 if let Some(answered) = self.answered_group_sender_key_repairs.get_mut(index) {
773 answered.last_responded_at_secs = now.get();
774 answered.request_created_at_secs = request.created_at.get();
775 answered.response_count = response_count;
776 answered.next_response_at_secs = next_response_at_secs;
777 }
778 } else {
779 self.answered_group_sender_key_repairs
780 .push(ProtocolAnsweredGroupSenderKeyRepair {
781 requester_owner_hex,
782 group_id: request.group_id.clone(),
783 sender_event_pubkey_hex,
784 key_id: request.key_id,
785 message_number: request.message_number,
786 required_revision: request.required_revision,
787 request_created_at_secs: request.created_at.get(),
788 last_responded_at_secs: now.get(),
789 response_count,
790 next_response_at_secs,
791 });
792 }
793 let excess = self
794 .answered_group_sender_key_repairs
795 .len()
796 .saturating_sub(ANSWERED_GROUP_SENDER_KEY_REPAIR_LIMIT);
797 if excess > 0 {
798 self.answered_group_sender_key_repairs.drain(0..excess);
799 }
800 }
801
802 fn clear_group_sender_key_repairs(
803 &mut self,
804 group_id: &str,
805 sender_event_pubkey: NdrDevicePubkey,
806 key_id: Option<u32>,
807 message_number: Option<u32>,
808 ) -> bool {
809 let original_len = self.pending_group_sender_key_repairs.len();
810 let sender_event_pubkey_hex = sender_event_pubkey.to_hex();
811 self.pending_group_sender_key_repairs.retain(|pending| {
812 let position_matches = match (key_id, message_number) {
813 (Some(key_id), Some(message_number)) => {
814 pending.key_id == Some(key_id) && pending.message_number == Some(message_number)
815 }
816 _ => true,
817 };
818 !(pending.group_id == group_id
819 && pending.sender_event_pubkey_hex == sender_event_pubkey_hex
820 && position_matches)
821 });
822 self.pending_group_sender_key_repairs.len() != original_len
823 }
824}