mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 13:36:30 +03:00
fix: receive_imf: Don't break 1:1 chat protection if received the verified Autocrypt key (#4597)
For example, broadcast list messages are sent unencrypted, but their Autocrypt header still contains the verified key. Thus we're sure that we still can encrypt to the peer and there's no need to break the existing protection.
This commit is contained in:
@@ -23,6 +23,7 @@ use crate::ephemeral::{stock_ephemeral_timer_changed, Timer as EphemeralTimer};
|
||||
use crate::events::EventType;
|
||||
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||
use crate::imap::{markseen_on_imap_table, GENERATED_PREFIX};
|
||||
use crate::key::DcKey;
|
||||
use crate::location;
|
||||
use crate::log::LogExt;
|
||||
use crate::message::{
|
||||
@@ -766,7 +767,18 @@ async fn add_parts(
|
||||
// That's why the config is checked here, and not above.
|
||||
&& context.get_config_bool(Config::VerifiedOneOnOneChats).await?
|
||||
{
|
||||
new_protection = ProtectionStatus::ProtectionBroken;
|
||||
let decryption_info = &mime_parser.decryption_info;
|
||||
new_protection =
|
||||
match decryption_info.autocrypt_header.as_ref().filter(|ah| {
|
||||
Some(&ah.public_key.fingerprint())
|
||||
== decryption_info
|
||||
.peerstate
|
||||
.as_ref()
|
||||
.and_then(|p| p.verified_key_fingerprint.as_ref())
|
||||
}) {
|
||||
Some(_) => chat.protected,
|
||||
None => ProtectionStatus::ProtectionBroken,
|
||||
};
|
||||
}
|
||||
if chat.protected != new_protection {
|
||||
// The message itself will be sorted under the device message since the device
|
||||
|
||||
@@ -136,6 +136,22 @@ impl TestContextManager {
|
||||
received_msg
|
||||
}
|
||||
|
||||
/// - Let one TestContext send a message.
|
||||
/// - Let the other TestContext receive it.
|
||||
/// - Assert that the message text is the formatted `err`.
|
||||
/// - Assert that the message info contains the original text.
|
||||
pub async fn send_recv_with_err(
|
||||
&self,
|
||||
from: &TestContext,
|
||||
to: &TestContext,
|
||||
err: &str,
|
||||
msg: &str,
|
||||
) -> Message {
|
||||
let received_msg = self.try_send_recv(from, to, msg).await;
|
||||
check_msg_with_err(to, &received_msg, err, msg).await;
|
||||
received_msg
|
||||
}
|
||||
|
||||
/// - Let one TestContext send a message
|
||||
/// - Let the other TestContext receive it
|
||||
pub async fn try_send_recv(&self, from: &TestContext, to: &TestContext, msg: &str) -> Message {
|
||||
@@ -1198,6 +1214,18 @@ async fn write_msg(context: &Context, prefix: &str, msg: &Message, buf: &mut Str
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// - Assert that the message text is the formatted error `err`.
|
||||
/// - Assert that the message info contains the original text.
|
||||
pub async fn check_msg_with_err(ctx: &TestContext, msg: &Message, err: &str, text: &str) {
|
||||
assert_eq!(msg.text, format!("[{err}]"));
|
||||
assert!(msg
|
||||
.id
|
||||
.get_info(ctx)
|
||||
.await
|
||||
.unwrap()
|
||||
.contains(&format!("\n\n{text}\n\n")));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use anyhow::Result;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::chat::{Chat, ProtectionStatus};
|
||||
use crate::chat::{add_contact_to_chat, create_broadcast_list, Chat, ProtectionStatus};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::config::Config;
|
||||
use crate::constants::DC_GCL_FOR_FORWARDING;
|
||||
@@ -12,7 +12,9 @@ use crate::mimefactory::MimeFactory;
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::stock_str;
|
||||
use crate::test_utils::{get_chat_msg, mark_as_verified, TestContext, TestContextManager};
|
||||
use crate::test_utils::{
|
||||
check_msg_with_err, get_chat_msg, mark_as_verified, TestContext, TestContextManager,
|
||||
};
|
||||
use crate::{e2ee, message};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
@@ -742,6 +744,45 @@ async fn test_create_oneonone_chat_with_former_verified_contact() -> Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Some messages are sent unencrypted, but they mustn't break a verified chat protection.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_unencrypted() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
enable_verified_oneonone_chats(&[&alice]).await;
|
||||
mark_as_verified(&alice, &bob).await;
|
||||
|
||||
let err_str = "This message is not encrypted. See 'Info' for more details";
|
||||
let msg = tcm.send_recv_with_err(&bob, &alice, err_str, "hi").await;
|
||||
assert!(!msg.get_showpadlock());
|
||||
let alice_chat = Chat::load_from_db(&alice, msg.chat_id).await?;
|
||||
assert!(alice_chat.is_protected());
|
||||
assert!(!alice_chat.is_protection_broken());
|
||||
|
||||
let broadcast_id = create_broadcast_list(&bob).await?;
|
||||
add_contact_to_chat(
|
||||
&bob,
|
||||
broadcast_id,
|
||||
bob.add_or_lookup_contact(&alice).await.id,
|
||||
)
|
||||
.await?;
|
||||
let sent_msg = bob.send_text(broadcast_id, "hi all").await;
|
||||
let msg = alice.recv_msg(&sent_msg).await;
|
||||
check_msg_with_err(&alice, &msg, err_str, "hi all").await;
|
||||
assert!(!msg.get_showpadlock());
|
||||
assert_eq!(msg.chat_id, alice_chat.id);
|
||||
let alice_chat = Chat::load_from_db(&alice, msg.chat_id).await?;
|
||||
assert!(alice_chat.is_protected());
|
||||
assert!(!alice_chat.is_protection_broken());
|
||||
|
||||
alice
|
||||
.golden_test_chat(alice_chat.id, "verified_chats_test_unencrypted")
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ============== Helper Functions ==============
|
||||
|
||||
async fn assert_verified(this: &TestContext, other: &TestContext, protected: ProtectionStatus) {
|
||||
|
||||
6
test-data/golden/verified_chats_test_unencrypted
Normal file
6
test-data/golden/verified_chats_test_unencrypted
Normal file
@@ -0,0 +1,6 @@
|
||||
Single#Chat#10: bob@example.net [bob@example.net] 🛡️
|
||||
--------------------------------------------------------------------------------
|
||||
Msg#10: info (Contact#Contact#Info): Messages are guaranteed to be end-to-end encrypted from now on. [NOTICED][INFO 🛡️]
|
||||
Msg#11: (Contact#Contact#10): [This message is not encrypted. See 'Info' for more details] [FRESH]
|
||||
Msg#12: (Contact#Contact#10): [This message is not encrypted. See 'Info' for more details] [FRESH]
|
||||
--------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user