mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 09:26:29 +03:00
fix: do not fail to send encrypted quotes to unencrypted chats
Replace quote text with "..." instead.
This commit is contained in:
@@ -1343,7 +1343,6 @@ def test_quote_encrypted(acfactory, lp):
|
|||||||
|
|
||||||
for quoted_msg in msg1, msg3:
|
for quoted_msg in msg1, msg3:
|
||||||
# Save the draft with a quote.
|
# Save the draft with a quote.
|
||||||
# It should be encrypted if quoted message is encrypted.
|
|
||||||
msg_draft = Message.new_empty(ac1, "text")
|
msg_draft = Message.new_empty(ac1, "text")
|
||||||
msg_draft.set_text("message reply")
|
msg_draft.set_text("message reply")
|
||||||
msg_draft.quote = quoted_msg
|
msg_draft.quote = quoted_msg
|
||||||
@@ -1357,10 +1356,14 @@ def test_quote_encrypted(acfactory, lp):
|
|||||||
chat.set_draft(None)
|
chat.set_draft(None)
|
||||||
assert chat.get_draft() is None
|
assert chat.get_draft() is None
|
||||||
|
|
||||||
|
# Quote should be replaced with "..." if quoted message is encrypted.
|
||||||
msg_in = ac2._evtracker.wait_next_incoming_message()
|
msg_in = ac2._evtracker.wait_next_incoming_message()
|
||||||
assert msg_in.text == "message reply"
|
assert msg_in.text == "message reply"
|
||||||
|
assert not msg_in.is_encrypted()
|
||||||
|
if quoted_msg.is_encrypted():
|
||||||
|
assert msg_in.quoted_text == "..."
|
||||||
|
else:
|
||||||
assert msg_in.quoted_text == quoted_msg.text
|
assert msg_in.quoted_text == quoted_msg.text
|
||||||
assert msg_in.is_encrypted() == quoted_msg.is_encrypted()
|
|
||||||
|
|
||||||
|
|
||||||
def test_quote_attachment(tmp_path, acfactory, lp):
|
def test_quote_attachment(tmp_path, acfactory, lp):
|
||||||
|
|||||||
@@ -1127,7 +1127,7 @@ impl Message {
|
|||||||
.get_bool(Param::GuaranteeE2ee)
|
.get_bool(Param::GuaranteeE2ee)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
{
|
{
|
||||||
self.param.set(Param::GuaranteeE2ee, "1");
|
self.param.set(Param::ProtectQuote, "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = quote.get_text();
|
let text = quote.get_text();
|
||||||
@@ -2015,7 +2015,9 @@ mod tests {
|
|||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::chat::{self, marknoticed_chat, send_text_msg, ChatItem};
|
use crate::chat::{
|
||||||
|
self, add_contact_to_chat, marknoticed_chat, send_text_msg, ChatItem, ProtectionStatus,
|
||||||
|
};
|
||||||
use crate::chatlist::Chatlist;
|
use crate::chatlist::Chatlist;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::reaction::send_reaction;
|
use crate::reaction::send_reaction;
|
||||||
@@ -2211,6 +2213,42 @@ mod tests {
|
|||||||
assert_eq!(quoted_msg.get_text(), msg2.quoted_text().unwrap());
|
assert_eq!(quoted_msg.get_text(), msg2.quoted_text().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn test_unencrypted_quote_encrypted_message() -> Result<()> {
|
||||||
|
let mut tcm = TestContextManager::new();
|
||||||
|
|
||||||
|
let alice = &tcm.alice().await;
|
||||||
|
let bob = &tcm.bob().await;
|
||||||
|
|
||||||
|
let alice_group = alice
|
||||||
|
.create_group_with_members(ProtectionStatus::Unprotected, "Group chat", &[bob])
|
||||||
|
.await;
|
||||||
|
let sent = alice.send_text(alice_group, "Hi! I created a group").await;
|
||||||
|
let bob_received_message = bob.recv_msg(&sent).await;
|
||||||
|
|
||||||
|
let bob_group = bob_received_message.chat_id;
|
||||||
|
bob_group.accept(bob).await?;
|
||||||
|
let sent = bob.send_text(bob_group, "Encrypted message").await;
|
||||||
|
let alice_received_message = alice.recv_msg(&sent).await;
|
||||||
|
assert!(alice_received_message.get_showpadlock());
|
||||||
|
|
||||||
|
// Alice adds contact without key so chat becomes unencrypted.
|
||||||
|
let alice_flubby_contact_id =
|
||||||
|
Contact::create(alice, "Flubby", "flubby@example.org").await?;
|
||||||
|
add_contact_to_chat(alice, alice_group, alice_flubby_contact_id).await?;
|
||||||
|
|
||||||
|
// Alice quotes encrypted message in unencrypted chat.
|
||||||
|
let mut msg = Message::new(Viewtype::Text);
|
||||||
|
msg.set_quote(alice, Some(&alice_received_message)).await?;
|
||||||
|
chat::send_msg(alice, alice_group, &mut msg).await?;
|
||||||
|
|
||||||
|
let bob_received_message = bob.recv_msg(&alice.pop_sent_msg().await).await;
|
||||||
|
assert_eq!(bob_received_message.quoted_text().unwrap(), "...");
|
||||||
|
assert_eq!(bob_received_message.get_showpadlock(), false);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_get_chat_id() {
|
async fn test_get_chat_id() {
|
||||||
// Alice receives a message that pops up as a contact request
|
// Alice receives a message that pops up as a contact request
|
||||||
|
|||||||
@@ -669,19 +669,19 @@ impl<'a> MimeFactory<'a> {
|
|||||||
|
|
||||||
let mut is_gossiped = false;
|
let mut is_gossiped = false;
|
||||||
|
|
||||||
let (main_part, parts) = match self.loaded {
|
|
||||||
Loaded::Message { .. } => {
|
|
||||||
self.render_message(context, &mut headers, &grpimage)
|
|
||||||
.await?
|
|
||||||
}
|
|
||||||
Loaded::Mdn { .. } => (self.render_mdn(context).await?, Vec::new()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let peerstates = self.peerstates_for_recipients(context).await?;
|
let peerstates = self.peerstates_for_recipients(context).await?;
|
||||||
let should_encrypt =
|
let should_encrypt =
|
||||||
encrypt_helper.should_encrypt(context, e2ee_guaranteed, &peerstates)?;
|
encrypt_helper.should_encrypt(context, e2ee_guaranteed, &peerstates)?;
|
||||||
let is_encrypted = should_encrypt && !force_plaintext;
|
let is_encrypted = should_encrypt && !force_plaintext;
|
||||||
|
|
||||||
|
let (main_part, parts) = match self.loaded {
|
||||||
|
Loaded::Message { .. } => {
|
||||||
|
self.render_message(context, &mut headers, &grpimage, is_encrypted)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
Loaded::Mdn { .. } => (self.render_mdn(context).await?, Vec::new()),
|
||||||
|
};
|
||||||
|
|
||||||
let message = if parts.is_empty() {
|
let message = if parts.is_empty() {
|
||||||
// Single part, render as regular message.
|
// Single part, render as regular message.
|
||||||
main_part
|
main_part
|
||||||
@@ -960,6 +960,7 @@ impl<'a> MimeFactory<'a> {
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
headers: &mut MessageHeaders,
|
headers: &mut MessageHeaders,
|
||||||
grpimage: &Option<String>,
|
grpimage: &Option<String>,
|
||||||
|
is_encrypted: bool,
|
||||||
) -> Result<(PartBuilder, Vec<PartBuilder>)> {
|
) -> Result<(PartBuilder, Vec<PartBuilder>)> {
|
||||||
let chat = match &self.loaded {
|
let chat = match &self.loaded {
|
||||||
Loaded::Message { chat } => chat,
|
Loaded::Message { chat } => chat,
|
||||||
@@ -1221,6 +1222,16 @@ impl<'a> MimeFactory<'a> {
|
|||||||
.msg
|
.msg
|
||||||
.quoted_text()
|
.quoted_text()
|
||||||
.map(|quote| format_flowed_quote("e) + "\r\n\r\n");
|
.map(|quote| format_flowed_quote("e) + "\r\n\r\n");
|
||||||
|
if !is_encrypted
|
||||||
|
&& self
|
||||||
|
.msg
|
||||||
|
.param
|
||||||
|
.get_bool(Param::ProtectQuote)
|
||||||
|
.unwrap_or_default()
|
||||||
|
{
|
||||||
|
// Message is not encrypted but quotes encrypted message.
|
||||||
|
quoted_text = Some("> ...\r\n\r\n".to_string());
|
||||||
|
}
|
||||||
if quoted_text.is_none() && final_text.starts_with('>') {
|
if quoted_text.is_none() && final_text.starts_with('>') {
|
||||||
// Insert empty line to avoid receiver treating user-sent quote as topquote inserted by
|
// Insert empty line to avoid receiver treating user-sent quote as topquote inserted by
|
||||||
// Delta Chat.
|
// Delta Chat.
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ pub enum Param {
|
|||||||
/// For Messages: message is encrypted, outgoing: guarantee E2EE or the message is not send
|
/// For Messages: message is encrypted, outgoing: guarantee E2EE or the message is not send
|
||||||
GuaranteeE2ee = b'c',
|
GuaranteeE2ee = b'c',
|
||||||
|
|
||||||
|
/// For Messages: quoted message is encrypted.
|
||||||
|
///
|
||||||
|
/// If this message is sent unencrypted, quote text should be replaced.
|
||||||
|
ProtectQuote = b'0',
|
||||||
|
|
||||||
/// For Messages: decrypted with validation errors or without mutual set, if neither
|
/// For Messages: decrypted with validation errors or without mutual set, if neither
|
||||||
/// 'c' nor 'e' are preset, the messages is only transport encrypted.
|
/// 'c' nor 'e' are preset, the messages is only transport encrypted.
|
||||||
ErroneousE2ee = b'e',
|
ErroneousE2ee = b'e',
|
||||||
|
|||||||
Reference in New Issue
Block a user