fix: Handle the case that the user starts a securejoin, and then deletes the contact (#7883)

fix https://github.com/chatmail/core/issues/7880

depends on #7754 (merged)

With this change, a securejoin message is just ignored if the contact
was deleted in the meantime; apparently the user is not interested in
the securejoin process anymore if they deleted the contact.

But other, parallel securejoin processes must not be affected; the test
also tests this.
This commit is contained in:
Hocuri
2026-03-02 22:11:05 +01:00
committed by GitHub
parent b85fa84a37
commit ab08a47298
2 changed files with 33 additions and 11 deletions

View File

@@ -304,7 +304,9 @@ async fn verify_sender_by_fingerprint(
fingerprint: &Fingerprint,
contact_id: ContactId,
) -> Result<bool> {
let contact = Contact::get_by_id(context, contact_id).await?;
let Some(contact) = Contact::get_by_id_optional(context, contact_id).await? else {
return Ok(false);
};
let is_verified = contact.fingerprint().is_some_and(|fp| &fp == fingerprint);
if is_verified {
mark_contact_id_as_verified(context, contact_id, Some(ContactId::SELF)).await?;

View File

@@ -910,7 +910,18 @@ async fn test_parallel_securejoin() -> Result<()> {
/// Tests Bob scanning setup contact QR codes of Alice and Fiona
/// concurrently.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parallel_setup_contact() -> Result<()> {
async fn test_parallel_setup_contact_basic() -> Result<()> {
test_parallel_setup_contact(false).await
}
/// Tests Bob scanning setup contact QR codes of Alice and Fiona
/// concurrently, and then deleting the Fiona contact.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parallel_setup_contact_bob_deletes_fiona() -> Result<()> {
test_parallel_setup_contact(true).await
}
async fn test_parallel_setup_contact(bob_deletes_fiona_contact: bool) -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
@@ -931,16 +942,25 @@ async fn test_parallel_setup_contact() -> Result<()> {
fiona.recv_msg_trash(&sent_fiona_vc_request).await;
let sent_fiona_vc_auth_required = fiona.pop_sent_msg().await;
bob.recv_msg_trash(&sent_fiona_vc_auth_required).await;
let sent_fiona_vc_request_with_auth = bob.pop_sent_msg().await;
fiona.recv_msg_trash(&sent_fiona_vc_request_with_auth).await;
let sent_fiona_vc_contact_confirm = fiona.pop_sent_msg().await;
bob.recv_msg_trash(&sent_fiona_vc_contact_confirm).await;
let bob_fiona_contact_id = bob.add_or_lookup_contact_id(fiona).await;
let bob_fiona_contact = Contact::get_by_id(bob, bob_fiona_contact_id).await.unwrap();
assert_eq!(bob_fiona_contact.is_verified(bob).await.unwrap(), true);
if bob_deletes_fiona_contact {
bob.get_chat(fiona).await.id.delete(bob).await?;
Contact::delete(bob, bob_fiona_contact_id).await?;
bob.recv_msg_trash(&sent_fiona_vc_auth_required).await;
let sent = bob.pop_sent_msg_opt(Duration::ZERO).await;
assert!(sent.is_none());
} else {
bob.recv_msg_trash(&sent_fiona_vc_auth_required).await;
let sent_fiona_vc_request_with_auth = bob.pop_sent_msg().await;
fiona.recv_msg_trash(&sent_fiona_vc_request_with_auth).await;
let sent_fiona_vc_contact_confirm = fiona.pop_sent_msg().await;
bob.recv_msg_trash(&sent_fiona_vc_contact_confirm).await;
let bob_fiona_contact = Contact::get_by_id(bob, bob_fiona_contact_id).await.unwrap();
assert_eq!(bob_fiona_contact.is_verified(bob).await.unwrap(), true);
}
// Alice gets online and previously started SecureJoin process finishes.
alice.recv_msg_trash(&sent_alice_vc_request).await;