mirror of
https://github.com/chatmail/core.git
synced 2026-05-02 04:46:29 +03:00
fix: receive_imf: Look up key contact by intended recipient fingerprint (#7661)
For now, do this only for `OneOneChat` and `MailingListOrBroadcast`, this is enough to correctly support messages from modern Delta Chat versions sending Intended Recipient Fingerprint subpackets and single-recipient messages from modern versions of other MUAs.
This commit is contained in:
@@ -196,7 +196,13 @@ pub async fn pk_encrypt(
|
|||||||
hashed.push(Subpacket::critical(SubpacketData::SignatureCreationTime(
|
hashed.push(Subpacket::critical(SubpacketData::SignatureCreationTime(
|
||||||
chrono::Utc::now().trunc_subsecs(0),
|
chrono::Utc::now().trunc_subsecs(0),
|
||||||
))?);
|
))?);
|
||||||
|
// Test "elena" uses old Delta Chat.
|
||||||
|
let skip = private_key_for_signing.dc_fingerprint().hex()
|
||||||
|
== "B86586B6DEF437D674BFAFC02A6B2EBC633B9E82";
|
||||||
for key in &public_keys_for_encryption {
|
for key in &public_keys_for_encryption {
|
||||||
|
if skip {
|
||||||
|
break;
|
||||||
|
}
|
||||||
let data = SubpacketData::IntendedRecipientFingerprint(key.fingerprint());
|
let data = SubpacketData::IntendedRecipientFingerprint(key.fingerprint());
|
||||||
let subpkt = match private_key_for_signing.version() < KeyVersion::V6 {
|
let subpkt = match private_key_for_signing.version() < KeyVersion::V6 {
|
||||||
true => Subpacket::regular(data)?,
|
true => Subpacket::regular(data)?,
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ use crate::events::EventType;
|
|||||||
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||||
use crate::imap::{GENERATED_PREFIX, markseen_on_imap_table};
|
use crate::imap::{GENERATED_PREFIX, markseen_on_imap_table};
|
||||||
use crate::key::{DcKey, Fingerprint};
|
use crate::key::{DcKey, Fingerprint};
|
||||||
use crate::key::{load_self_public_key_opt, self_fingerprint, self_fingerprint_opt};
|
use crate::key::{
|
||||||
|
load_self_public_key, load_self_public_key_opt, self_fingerprint, self_fingerprint_opt,
|
||||||
|
};
|
||||||
use crate::log::{LogExt as _, warn};
|
use crate::log::{LogExt as _, warn};
|
||||||
use crate::message::{
|
use crate::message::{
|
||||||
self, Message, MessageState, MessengerMessage, MsgId, Viewtype, rfc724_mid_exists,
|
self, Message, MessageState, MessengerMessage, MsgId, Viewtype, rfc724_mid_exists,
|
||||||
@@ -386,8 +388,30 @@ async fn get_to_and_past_contact_ids(
|
|||||||
// This is an encrypted 1:1 chat.
|
// This is an encrypted 1:1 chat.
|
||||||
to_ids = pgp_to_ids
|
to_ids = pgp_to_ids
|
||||||
} else {
|
} else {
|
||||||
let ids = match mime_parser.was_encrypted() {
|
let ids = if mime_parser.was_encrypted() {
|
||||||
true => {
|
let mut recipient_fps = mime_parser
|
||||||
|
.signature
|
||||||
|
.as_ref()
|
||||||
|
.map(|(_, recipient_fps)| recipient_fps.iter().cloned().collect::<Vec<_>>())
|
||||||
|
.unwrap_or_default();
|
||||||
|
// If there are extra recipient fingerprints, it may be a non-chat "implicit
|
||||||
|
// Bcc" message. Fall back to in-chat lookup if so.
|
||||||
|
if !recipient_fps.is_empty() && recipient_fps.len() <= 2 {
|
||||||
|
let self_fp = load_self_public_key(context).await?.dc_fingerprint();
|
||||||
|
recipient_fps.retain(|fp| *fp != self_fp);
|
||||||
|
if recipient_fps.is_empty() {
|
||||||
|
vec![Some(ContactId::SELF)]
|
||||||
|
} else {
|
||||||
|
add_or_lookup_key_contacts(
|
||||||
|
context,
|
||||||
|
&mime_parser.recipients,
|
||||||
|
&mime_parser.gossiped_keys,
|
||||||
|
&recipient_fps,
|
||||||
|
Origin::Hidden,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
lookup_key_contacts_fallback_to_chat(
|
lookup_key_contacts_fallback_to_chat(
|
||||||
context,
|
context,
|
||||||
&mime_parser.recipients,
|
&mime_parser.recipients,
|
||||||
@@ -396,7 +420,8 @@ async fn get_to_and_past_contact_ids(
|
|||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
false => vec![],
|
} else {
|
||||||
|
vec![]
|
||||||
};
|
};
|
||||||
if mime_parser.was_encrypted() && !ids.contains(&None)
|
if mime_parser.was_encrypted() && !ids.contains(&None)
|
||||||
// Prefer creating PGP chats if there are any key-contacts. At least this prevents
|
// Prefer creating PGP chats if there are any key-contacts. At least this prevents
|
||||||
|
|||||||
@@ -5111,9 +5111,9 @@ async fn test_dont_verify_by_verified_by_unknown() -> Result<()> {
|
|||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_recv_outgoing_msg_before_securejoin() -> Result<()> {
|
async fn test_recv_outgoing_msg_before_securejoin() -> Result<()> {
|
||||||
let mut tcm = TestContextManager::new();
|
let mut tcm = TestContextManager::new();
|
||||||
let a0 = &tcm.alice().await;
|
|
||||||
let a1 = &tcm.alice().await;
|
|
||||||
let bob = &tcm.bob().await;
|
let bob = &tcm.bob().await;
|
||||||
|
let a0 = &tcm.elena().await;
|
||||||
|
let a1 = &tcm.elena().await;
|
||||||
|
|
||||||
tcm.execute_securejoin(bob, a0).await;
|
tcm.execute_securejoin(bob, a0).await;
|
||||||
let chat_id_a0_bob = a0.create_chat_id(bob).await;
|
let chat_id_a0_bob = a0.create_chat_id(bob).await;
|
||||||
@@ -5154,14 +5154,31 @@ async fn test_recv_outgoing_msg_before_securejoin() -> Result<()> {
|
|||||||
chat_a1.why_cant_send(a1).await?,
|
chat_a1.why_cant_send(a1).await?,
|
||||||
Some(CantSendReason::ContactRequest)
|
Some(CantSendReason::ContactRequest)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let a0 = &tcm.alice().await;
|
||||||
|
let a1 = &tcm.alice().await;
|
||||||
|
tcm.execute_securejoin(bob, a0).await;
|
||||||
|
let chat_id_a0_bob = a0.create_chat_id(bob).await;
|
||||||
|
let sent_msg = a0.send_text(chat_id_a0_bob, "Hi").await;
|
||||||
|
bob.recv_msg(&sent_msg).await;
|
||||||
|
let msg_a1 = a1.recv_msg(&sent_msg).await;
|
||||||
|
assert!(msg_a1.get_showpadlock());
|
||||||
|
let chat_a1 = Chat::load_from_db(a1, msg_a1.chat_id).await?;
|
||||||
|
assert_eq!(chat_a1.typ, Chattype::Single);
|
||||||
|
assert!(chat_a1.is_encrypted(a1).await?);
|
||||||
|
assert_eq!(
|
||||||
|
chat::get_chat_contacts(a1, chat_a1.id).await?,
|
||||||
|
[a1.add_or_lookup_contact_id(bob).await]
|
||||||
|
);
|
||||||
|
assert!(chat_a1.can_send(a1).await?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_recv_outgoing_msg_before_having_key_and_after() -> Result<()> {
|
async fn test_recv_outgoing_msg_before_having_key_and_after() -> Result<()> {
|
||||||
let mut tcm = TestContextManager::new();
|
let mut tcm = TestContextManager::new();
|
||||||
let a0 = &tcm.alice().await;
|
let a0 = &tcm.elena().await;
|
||||||
let a1 = &tcm.alice().await;
|
let a1 = &tcm.elena().await;
|
||||||
let bob = &tcm.bob().await;
|
let bob = &tcm.bob().await;
|
||||||
|
|
||||||
tcm.execute_securejoin(bob, a0).await;
|
tcm.execute_securejoin(bob, a0).await;
|
||||||
@@ -5174,9 +5191,9 @@ async fn test_recv_outgoing_msg_before_having_key_and_after() -> Result<()> {
|
|||||||
assert!(!chat_a1.is_encrypted(a1).await?);
|
assert!(!chat_a1.is_encrypted(a1).await?);
|
||||||
|
|
||||||
// Device a1 somehow learns Bob's key and creates the corresponding chat. However, this doesn't
|
// Device a1 somehow learns Bob's key and creates the corresponding chat. However, this doesn't
|
||||||
// help currently because we only look up key contacts by address in a particular chat and the
|
// help because we only look up key contacts by address in a particular chat and the new chat
|
||||||
// new chat isn't referenced by the received message. This should be fixed by sending and
|
// isn't referenced by the received message. This is fixed by sending and receiving Intended
|
||||||
// receiving Intended Recipient Fingerprint subpackets.
|
// Recipient Fingerprint subpackets which elena doesn't send.
|
||||||
a1.create_chat_id(bob).await;
|
a1.create_chat_id(bob).await;
|
||||||
let sent_msg = a0.send_text(chat_id_a0_bob, "Hi again").await;
|
let sent_msg = a0.send_text(chat_id_a0_bob, "Hi again").await;
|
||||||
let msg_a1 = a1.recv_msg(&sent_msg).await;
|
let msg_a1 = a1.recv_msg(&sent_msg).await;
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ impl TestContextManager {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns new elena's "device".
|
||||||
|
/// Elena doesn't send Intended Recipient Fingerprint subpackets to simulate old Delta Chat.
|
||||||
pub async fn elena(&mut self) -> TestContext {
|
pub async fn elena(&mut self) -> TestContext {
|
||||||
TestContext::builder()
|
TestContext::builder()
|
||||||
.configure_elena()
|
.configure_elena()
|
||||||
|
|||||||
Reference in New Issue
Block a user