mirror of
https://github.com/chatmail/core.git
synced 2026-05-03 21:36:29 +03:00
feat: add "e2ee encrypted" info message to all e2ee chats (#7008)
this PR adds a info message "messages are end-to-end-encrypted" also for chats created by eg. vcards. by the removal of lock icons, this is a good place to hint for that in addition; this is also what eg. whatsapp and others are doing the wording itself is tweaked at https://github.com/deltachat/deltachat-android/pull/3817 (and there is also the rough idea to make the message a little more outstanding, by some more dedicated colors) ~~did not test in practise, if this leads to double "e2ee info messages" on secure join, tests look good, however.~~ EDIT: did lots of practise tests meanwhile :) most of the changes in this PR are about test ... ftr, in another PR, after 2.0 reeases, there could probably quite some code cleanup wrt set-protection, protection-disabled etc. --------- Co-authored-by: Hocuri <hocuri@gmx.de>
This commit is contained in:
42
src/chat.rs
42
src/chat.rs
@@ -349,6 +349,8 @@ impl ChatId {
|
||||
chat_id
|
||||
.add_protection_msg(context, ProtectionStatus::Protected, None, timestamp)
|
||||
.await?;
|
||||
} else {
|
||||
chat_id.maybe_add_encrypted_msg(context, timestamp).await?;
|
||||
}
|
||||
|
||||
info!(
|
||||
@@ -604,6 +606,42 @@ impl ChatId {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Adds message "Messages are end-to-end encrypted" if appropriate.
|
||||
///
|
||||
/// This function is rather slow because it does a lot of database queries,
|
||||
/// but this is fine because it is only called on chat creation.
|
||||
async fn maybe_add_encrypted_msg(self, context: &Context, timestamp_sort: i64) -> Result<()> {
|
||||
let chat = Chat::load_from_db(context, self).await?;
|
||||
|
||||
// as secure-join adds its own message on success (after some other messasges),
|
||||
// we do not want to add "Messages are end-to-end encrypted" on chat creation.
|
||||
// we detect secure join by `can_send` (for Bob, scanner side) and by `blocked` (for Alice, inviter side) below.
|
||||
if !chat.is_encrypted(context).await?
|
||||
|| self <= DC_CHAT_ID_LAST_SPECIAL
|
||||
|| chat.is_device_talk()
|
||||
|| chat.is_self_talk()
|
||||
|| (!chat.can_send(context).await? && !chat.is_contact_request())
|
||||
|| chat.blocked == Blocked::Yes
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let text = stock_str::messages_e2e_encrypted(context).await;
|
||||
add_info_msg_with_cmd(
|
||||
context,
|
||||
self,
|
||||
&text,
|
||||
SystemMessage::ChatE2ee,
|
||||
timestamp_sort,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets protection and adds a message.
|
||||
///
|
||||
/// `timestamp_sort` is used as the timestamp of the added message
|
||||
@@ -2673,6 +2711,10 @@ impl ChatIdBlocked {
|
||||
smeared_time,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
chat_id
|
||||
.maybe_add_encrypted_msg(context, smeared_time)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::message::{MessengerMessage, delete_msgs};
|
||||
use crate::mimeparser::{self, MimeMessage};
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::test_utils::{
|
||||
AVATAR_64x64_BYTES, AVATAR_64x64_DEDUPLICATED, TestContext, TestContextManager,
|
||||
AVATAR_64x64_BYTES, AVATAR_64x64_DEDUPLICATED, E2EE_INFO_MSGS, TestContext, TestContextManager,
|
||||
TimeShiftFalsePositiveNote, sync,
|
||||
};
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -2104,7 +2104,7 @@ async fn test_forward_basic() -> Result<()> {
|
||||
forward_msgs(&bob, &[msg.id], bob_chat.get_id()).await?;
|
||||
|
||||
let forwarded_msg = bob.pop_sent_msg().await;
|
||||
assert_eq!(bob_chat.id.get_msg_cnt(&bob).await?, 2);
|
||||
assert_eq!(bob_chat.id.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 2);
|
||||
assert_ne!(
|
||||
forwarded_msg.load_from_db().await.rfc724_mid,
|
||||
msg.rfc724_mid,
|
||||
@@ -2132,7 +2132,7 @@ async fn test_forward_info_msg() -> Result<()> {
|
||||
assert!(msg1.get_text().contains("bob@example.net"));
|
||||
|
||||
let chat_id2 = ChatId::create_for_contact(alice, bob_id).await?;
|
||||
assert_eq!(get_chat_msgs(alice, chat_id2).await?.len(), 0);
|
||||
assert_eq!(get_chat_msgs(alice, chat_id2).await?.len(), E2EE_INFO_MSGS);
|
||||
forward_msgs(alice, &[msg1.id], chat_id2).await?;
|
||||
let msg2 = alice.get_last_msg_in(chat_id2).await;
|
||||
assert!(!msg2.is_info()); // forwarded info-messages lose their info-state
|
||||
@@ -2518,22 +2518,34 @@ async fn test_resend_own_message() -> Result<()> {
|
||||
let sent1_ts_sent = msg.timestamp_sent;
|
||||
assert_eq!(msg.get_text(), "alice->bob");
|
||||
assert_eq!(get_chat_contacts(&bob, msg.chat_id).await?.len(), 2);
|
||||
assert_eq!(get_chat_msgs(&bob, msg.chat_id).await?.len(), 1);
|
||||
assert_eq!(
|
||||
get_chat_msgs(&bob, msg.chat_id).await?.len(),
|
||||
E2EE_INFO_MSGS + 1
|
||||
);
|
||||
bob.recv_msg(&sent2).await;
|
||||
assert_eq!(get_chat_contacts(&bob, msg.chat_id).await?.len(), 3);
|
||||
assert_eq!(get_chat_msgs(&bob, msg.chat_id).await?.len(), 2);
|
||||
assert_eq!(
|
||||
get_chat_msgs(&bob, msg.chat_id).await?.len(),
|
||||
E2EE_INFO_MSGS + 2
|
||||
);
|
||||
let received = bob.recv_msg_opt(&sent3).await;
|
||||
// No message should actually be added since we already know this message:
|
||||
assert!(received.is_none());
|
||||
assert_eq!(get_chat_contacts(&bob, msg.chat_id).await?.len(), 3);
|
||||
assert_eq!(get_chat_msgs(&bob, msg.chat_id).await?.len(), 2);
|
||||
assert_eq!(
|
||||
get_chat_msgs(&bob, msg.chat_id).await?.len(),
|
||||
E2EE_INFO_MSGS + 2
|
||||
);
|
||||
|
||||
// Fiona does not receive the first message, however, due to resending, she has a similar view as Alice and Bob
|
||||
fiona.recv_msg(&sent2).await;
|
||||
let msg = fiona.recv_msg(&sent3).await;
|
||||
assert_eq!(msg.get_text(), "alice->bob");
|
||||
assert_eq!(get_chat_contacts(&fiona, msg.chat_id).await?.len(), 3);
|
||||
assert_eq!(get_chat_msgs(&fiona, msg.chat_id).await?.len(), 2);
|
||||
assert_eq!(
|
||||
get_chat_msgs(&fiona, msg.chat_id).await?.len(),
|
||||
E2EE_INFO_MSGS + 2
|
||||
);
|
||||
let msg_from = Contact::get_by_id(&fiona, msg.get_from_id()).await?;
|
||||
assert_eq!(msg_from.get_addr(), "alice@example.org");
|
||||
assert!(sent1_ts_sent < msg.timestamp_sent);
|
||||
@@ -4454,13 +4466,13 @@ async fn test_receive_edit_request_after_removal() -> Result<()> {
|
||||
let bob_msg = bob.recv_msg(&sent1).await;
|
||||
let bob_chat_id = bob_msg.chat_id;
|
||||
assert_eq!(bob_msg.text, "zext me in delra.cat");
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(bob).await?, 1);
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(bob).await?, E2EE_INFO_MSGS + 1);
|
||||
|
||||
delete_msgs(bob, &[bob_msg.id]).await?;
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(bob).await?, 0);
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(bob).await?, E2EE_INFO_MSGS);
|
||||
|
||||
bob.recv_msg_trash(&sent2).await;
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(bob).await?, 0);
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(bob).await?, E2EE_INFO_MSGS);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -4549,28 +4561,34 @@ async fn test_send_delete_request() -> Result<()> {
|
||||
// Alice sends a message, then sends a deletion request
|
||||
let sent1 = alice.send_text(alice_chat.id, "wtf").await;
|
||||
let alice_msg = sent1.load_from_db().await;
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(alice).await?, 2);
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(alice).await?, E2EE_INFO_MSGS + 2);
|
||||
|
||||
message::delete_msgs_ex(alice, &[alice_msg.id], true).await?;
|
||||
let sent2 = alice.pop_sent_msg().await;
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(alice).await?, 1);
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(alice).await?, E2EE_INFO_MSGS + 1);
|
||||
|
||||
// Bob receives both messages and has nothing the end
|
||||
let bob_msg = bob.recv_msg(&sent1).await;
|
||||
assert_eq!(bob_msg.text, "wtf");
|
||||
assert_eq!(bob_msg.chat_id.get_msg_cnt(bob).await?, 2);
|
||||
assert_eq!(bob_msg.chat_id.get_msg_cnt(bob).await?, E2EE_INFO_MSGS + 2);
|
||||
|
||||
bob.recv_msg_opt(&sent2).await;
|
||||
assert_eq!(bob_msg.chat_id.get_msg_cnt(bob).await?, 1);
|
||||
assert_eq!(bob_msg.chat_id.get_msg_cnt(bob).await?, E2EE_INFO_MSGS + 1);
|
||||
|
||||
// Alice has another device, and there is also nothing at the end
|
||||
let alice2 = &tcm.alice().await;
|
||||
alice2.recv_msg(&sent0).await;
|
||||
let alice2_msg = alice2.recv_msg(&sent1).await;
|
||||
assert_eq!(alice2_msg.chat_id.get_msg_cnt(alice2).await?, 2);
|
||||
assert_eq!(
|
||||
alice2_msg.chat_id.get_msg_cnt(alice2).await?,
|
||||
E2EE_INFO_MSGS + 2
|
||||
);
|
||||
|
||||
alice2.recv_msg_opt(&sent2).await;
|
||||
assert_eq!(alice2_msg.chat_id.get_msg_cnt(alice2).await?, 1);
|
||||
assert_eq!(
|
||||
alice2_msg.chat_id.get_msg_cnt(alice2).await?,
|
||||
E2EE_INFO_MSGS + 1
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::chatlist::Chatlist;
|
||||
use crate::constants::Chattype;
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::test_utils::{TestContext, get_chat_msg};
|
||||
use crate::test_utils::{E2EE_INFO_MSGS, TestContext, get_chat_msg};
|
||||
use crate::tools::{SystemTime, create_outgoing_rfc724_mid};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
@@ -571,7 +571,7 @@ async fn test_get_next_msgs() -> Result<()> {
|
||||
|
||||
let alice_chat = alice.create_chat(&bob).await;
|
||||
|
||||
assert!(alice.get_next_msgs().await?.is_empty());
|
||||
assert_eq!(alice.get_next_msgs().await?.len(), E2EE_INFO_MSGS);
|
||||
assert!(bob.get_next_msgs().await?.is_empty());
|
||||
|
||||
let sent_msg = alice.send_text(alice_chat.id, "Hi Bob").await;
|
||||
|
||||
@@ -277,7 +277,7 @@ mod tests {
|
||||
use crate::chat::{get_chat_msgs, send_msg};
|
||||
use crate::ephemeral::Timer;
|
||||
use crate::receive_imf::receive_imf_from_inbox;
|
||||
use crate::test_utils::TestContext;
|
||||
use crate::test_utils::{E2EE_INFO_MSGS, TestContext};
|
||||
|
||||
#[test]
|
||||
fn test_downloadstate_values() {
|
||||
@@ -459,7 +459,10 @@ mod tests {
|
||||
.await?;
|
||||
let msg = bob.get_last_msg().await;
|
||||
let chat_id = msg.chat_id;
|
||||
assert_eq!(get_chat_msgs(&bob, chat_id).await?.len(), 1);
|
||||
assert_eq!(
|
||||
get_chat_msgs(&bob, chat_id).await?.len(),
|
||||
E2EE_INFO_MSGS + 1
|
||||
);
|
||||
assert_eq!(msg.download_state(), DownloadState::Available);
|
||||
|
||||
// downloading the status update afterwards expands to nothing and moves the placeholder to trash-chat
|
||||
@@ -472,7 +475,7 @@ mod tests {
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(get_chat_msgs(&bob, chat_id).await?.len(), 0);
|
||||
assert_eq!(get_chat_msgs(&bob, chat_id).await?.len(), E2EE_INFO_MSGS);
|
||||
assert!(
|
||||
Message::load_from_db_optional(&bob, msg.id)
|
||||
.await?
|
||||
|
||||
@@ -963,6 +963,7 @@ impl Message {
|
||||
| SystemMessage::SecurejoinMessage
|
||||
| SystemMessage::LocationStreamingEnabled
|
||||
| SystemMessage::LocationOnly
|
||||
| SystemMessage::ChatE2ee
|
||||
| SystemMessage::ChatProtectionEnabled
|
||||
| SystemMessage::ChatProtectionDisabled
|
||||
| SystemMessage::InvalidUnencryptedMail
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::config::Config;
|
||||
use crate::reaction::send_reaction;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::test_utils;
|
||||
use crate::test_utils::{TestContext, TestContextManager};
|
||||
use crate::test_utils::{E2EE_INFO_MSGS, TestContext, TestContextManager};
|
||||
|
||||
#[test]
|
||||
fn test_guess_msgtype_from_suffix() {
|
||||
@@ -347,7 +347,7 @@ async fn test_markseen_msgs() -> Result<()> {
|
||||
let chats = Chatlist::try_load(&bob, 0, None, None).await?;
|
||||
assert_eq!(chats.len(), 1);
|
||||
let msgs = chat::get_chat_msgs(&bob, bob_chat_id).await?;
|
||||
assert_eq!(msgs.len(), 2);
|
||||
assert_eq!(msgs.len(), E2EE_INFO_MSGS + 2);
|
||||
assert_eq!(bob.get_fresh_msgs().await?.len(), 0);
|
||||
|
||||
// that has no effect in contact request
|
||||
@@ -358,7 +358,7 @@ async fn test_markseen_msgs() -> Result<()> {
|
||||
assert_eq!(bob_chat.blocked, Blocked::Request);
|
||||
|
||||
let msgs = chat::get_chat_msgs(&bob, bob_chat_id).await?;
|
||||
assert_eq!(msgs.len(), 2);
|
||||
assert_eq!(msgs.len(), E2EE_INFO_MSGS + 2);
|
||||
bob_chat_id.accept(&bob).await.unwrap();
|
||||
|
||||
// bob sends to alice,
|
||||
@@ -761,19 +761,22 @@ async fn test_delete_msgs_sync() -> Result<()> {
|
||||
|
||||
// Alice sends a messsage and receives it on the other device
|
||||
let sent1 = alice.send_text(alice_chat_id, "foo").await;
|
||||
assert_eq!(alice_chat_id.get_msg_cnt(alice).await?, 1);
|
||||
assert_eq!(alice_chat_id.get_msg_cnt(alice).await?, E2EE_INFO_MSGS + 1);
|
||||
|
||||
let msg = alice2.recv_msg(&sent1).await;
|
||||
let alice2_chat_id = msg.chat_id;
|
||||
assert_eq!(alice2.get_last_msg_in(alice2_chat_id).await.id, msg.id);
|
||||
assert_eq!(alice2_chat_id.get_msg_cnt(alice2).await?, 1);
|
||||
assert_eq!(
|
||||
alice2_chat_id.get_msg_cnt(alice2).await?,
|
||||
E2EE_INFO_MSGS + 1
|
||||
);
|
||||
|
||||
// Alice deletes the message; this should happen on both devices as well
|
||||
delete_msgs(alice, &[sent1.sender_msg_id]).await?;
|
||||
assert_eq!(alice_chat_id.get_msg_cnt(alice).await?, 0);
|
||||
assert_eq!(alice_chat_id.get_msg_cnt(alice).await?, E2EE_INFO_MSGS);
|
||||
|
||||
test_utils::sync(alice, alice2).await;
|
||||
assert_eq!(alice2_chat_id.get_msg_cnt(alice2).await?, 0);
|
||||
assert_eq!(alice2_chat_id.get_msg_cnt(alice2).await?, E2EE_INFO_MSGS);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -181,10 +181,10 @@ pub enum SystemMessage {
|
||||
/// Chat ephemeral message timer is changed.
|
||||
EphemeralTimerChanged = 10,
|
||||
|
||||
/// "Messages are guaranteed to be end-to-end encrypted from now on."
|
||||
/// "Messages are end-to-end encrypted."
|
||||
ChatProtectionEnabled = 11,
|
||||
|
||||
/// "%1$s sent a message from another device."
|
||||
/// "%1$s sent a message from another device.", deprecated 2025-07
|
||||
ChatProtectionDisabled = 12,
|
||||
|
||||
/// Message can't be sent because of `Invalid unencrypted mail to <>`
|
||||
@@ -213,6 +213,9 @@ pub enum SystemMessage {
|
||||
|
||||
/// This message contains a users iroh node address.
|
||||
IrohNodeAddr = 40,
|
||||
|
||||
/// "Messages are end-to-end encrypted."
|
||||
ChatE2ee = 50,
|
||||
}
|
||||
|
||||
const MIME_AC_SETUP_FILE: &str = "application/autocrypt-setup";
|
||||
|
||||
@@ -407,6 +407,7 @@ mod tests {
|
||||
use crate::message::{MessageState, delete_msgs};
|
||||
use crate::receive_imf::{receive_imf, receive_imf_from_inbox};
|
||||
use crate::sql::housekeeping;
|
||||
use crate::test_utils::E2EE_INFO_MSGS;
|
||||
use crate::test_utils::TestContext;
|
||||
use crate::test_utils::TestContextManager;
|
||||
use crate::tools::SystemTime;
|
||||
@@ -653,13 +654,25 @@ Here's my footer -- bob@example.net"
|
||||
let chat_alice = alice.create_chat(&bob).await;
|
||||
let alice_msg = alice.send_text(chat_alice.id, "Hi!").await;
|
||||
let bob_msg = bob.recv_msg(&alice_msg).await;
|
||||
assert_eq!(get_chat_msgs(&alice, chat_alice.id).await?.len(), 1);
|
||||
assert_eq!(get_chat_msgs(&bob, bob_msg.chat_id).await?.len(), 1);
|
||||
assert_eq!(
|
||||
get_chat_msgs(&alice, chat_alice.id).await?.len(),
|
||||
E2EE_INFO_MSGS + 1
|
||||
);
|
||||
assert_eq!(
|
||||
get_chat_msgs(&bob, bob_msg.chat_id).await?.len(),
|
||||
E2EE_INFO_MSGS + 1
|
||||
);
|
||||
|
||||
let alice_msg2 = alice.send_text(chat_alice.id, "Hi again!").await;
|
||||
bob.recv_msg(&alice_msg2).await;
|
||||
assert_eq!(get_chat_msgs(&alice, chat_alice.id).await?.len(), 2);
|
||||
assert_eq!(get_chat_msgs(&bob, bob_msg.chat_id).await?.len(), 2);
|
||||
assert_eq!(
|
||||
get_chat_msgs(&alice, chat_alice.id).await?.len(),
|
||||
E2EE_INFO_MSGS + 2
|
||||
);
|
||||
assert_eq!(
|
||||
get_chat_msgs(&bob, bob_msg.chat_id).await?.len(),
|
||||
E2EE_INFO_MSGS + 2
|
||||
);
|
||||
|
||||
bob_msg.chat_id.accept(&bob).await?;
|
||||
|
||||
@@ -667,12 +680,18 @@ Here's my footer -- bob@example.net"
|
||||
send_reaction(&bob, bob_msg.id, "👍").await.unwrap();
|
||||
expect_reactions_changed_event(&bob, bob_msg.chat_id, bob_msg.id, ContactId::SELF).await?;
|
||||
expect_no_unwanted_events(&bob).await;
|
||||
assert_eq!(get_chat_msgs(&bob, bob_msg.chat_id).await?.len(), 2);
|
||||
assert_eq!(
|
||||
get_chat_msgs(&bob, bob_msg.chat_id).await?.len(),
|
||||
E2EE_INFO_MSGS + 2
|
||||
);
|
||||
|
||||
let bob_reaction_msg = bob.pop_sent_msg().await;
|
||||
let alice_reaction_msg = alice.recv_msg_hidden(&bob_reaction_msg).await;
|
||||
assert_eq!(alice_reaction_msg.state, MessageState::InFresh);
|
||||
assert_eq!(get_chat_msgs(&alice, chat_alice.id).await?.len(), 2);
|
||||
assert_eq!(
|
||||
get_chat_msgs(&alice, chat_alice.id).await?.len(),
|
||||
E2EE_INFO_MSGS + 2
|
||||
);
|
||||
|
||||
let reactions = get_msg_reactions(&alice, alice_msg.sender_msg_id).await?;
|
||||
assert_eq!(reactions.to_string(), "👍1");
|
||||
|
||||
@@ -15,8 +15,9 @@ use crate::download::MIN_DOWNLOAD_LIMIT;
|
||||
use crate::imap::prefetch_should_download;
|
||||
use crate::imex::{ImexMode, imex};
|
||||
use crate::securejoin::get_securejoin_qr;
|
||||
use crate::test_utils::mark_as_verified;
|
||||
use crate::test_utils::{TestContext, TestContextManager, get_chat_msg};
|
||||
use crate::test_utils::{
|
||||
E2EE_INFO_MSGS, TestContext, TestContextManager, get_chat_msg, mark_as_verified,
|
||||
};
|
||||
use crate::tools::{SystemTime, time};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
@@ -133,7 +134,7 @@ async fn test_adhoc_group_outgoing_show_accepted_contact_unaccepted() -> Result<
|
||||
let chats = Chatlist::try_load(bob, 0, None, None).await?;
|
||||
assert_eq!(chats.len(), 1);
|
||||
let chat_id = chats.get_chat_id(0)?;
|
||||
assert_eq!(chat_id.get_msg_cnt(bob).await?, 1);
|
||||
assert_eq!(chat_id.get_msg_cnt(bob).await?, E2EE_INFO_MSGS + 1);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4410,7 +4411,7 @@ async fn test_create_group_with_big_msg() -> Result<()> {
|
||||
|
||||
// The big message must go away from the 1:1 chat.
|
||||
let msgs = chat::get_chat_msgs(&alice, ab_chat_id).await?;
|
||||
assert!(msgs.is_empty());
|
||||
assert_eq!(msgs.len(), E2EE_INFO_MSGS);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::chatlist::Chatlist;
|
||||
use crate::constants::Chattype;
|
||||
use crate::key::self_fingerprint;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::stock_str::{self, chat_protection_enabled};
|
||||
use crate::stock_str::{self, messages_e2e_encrypted};
|
||||
use crate::test_utils::{
|
||||
TestContext, TestContextManager, TimeShiftFalsePositiveNote, get_chat_msg,
|
||||
};
|
||||
@@ -246,7 +246,7 @@ async fn test_setup_contact_ex(case: SetupContactCase) {
|
||||
let chat = alice.get_chat(&bob).await;
|
||||
let msg = get_chat_msg(&alice, chat.get_id(), 0, 1).await;
|
||||
assert!(msg.is_info());
|
||||
let expected_text = chat_protection_enabled(&alice).await;
|
||||
let expected_text = messages_e2e_encrypted(&alice).await;
|
||||
assert_eq!(msg.get_text(), expected_text);
|
||||
if case == SetupContactCase::CheckProtectionTimestamp {
|
||||
assert_eq!(msg.timestamp_sort, vc_request_with_auth_ts_sent + 1);
|
||||
@@ -296,7 +296,7 @@ async fn test_setup_contact_ex(case: SetupContactCase) {
|
||||
assert_eq!(msg.get_text(), stock_str::securejoin_wait(&bob).await);
|
||||
let msg = get_chat_msg(&bob, bob_chat.get_id(), i.next().unwrap(), msg_cnt).await;
|
||||
assert!(msg.is_info());
|
||||
assert_eq!(msg.get_text(), chat_protection_enabled(&bob).await);
|
||||
assert_eq!(msg.get_text(), messages_e2e_encrypted(&bob).await);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
@@ -540,7 +540,7 @@ async fn test_secure_join() -> Result<()> {
|
||||
// - You added member bob@example.net
|
||||
let msg = get_chat_msg(&alice, alice_chatid, 0, 2).await;
|
||||
assert!(msg.is_info());
|
||||
let expected_text = chat_protection_enabled(&alice).await;
|
||||
let expected_text = messages_e2e_encrypted(&alice).await;
|
||||
assert_eq!(msg.get_text(), expected_text);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -65,9 +65,6 @@ pub enum StockMessage {
|
||||
#[strum(props(fallback = "GIF"))]
|
||||
Gif = 23,
|
||||
|
||||
#[strum(props(fallback = "Encrypted message"))]
|
||||
EncryptedMsg = 24,
|
||||
|
||||
#[strum(props(fallback = "End-to-end encryption available"))]
|
||||
E2eAvailable = 25,
|
||||
|
||||
@@ -380,9 +377,10 @@ pub enum StockMessage {
|
||||
#[strum(props(fallback = "I left the group."))]
|
||||
MsgILeftGroup = 166,
|
||||
|
||||
#[strum(props(fallback = "Messages are guaranteed to be end-to-end encrypted from now on."))]
|
||||
#[strum(props(fallback = "Messages are end-to-end encrypted."))]
|
||||
ChatProtectionEnabled = 170,
|
||||
|
||||
// deprecated 2025-07
|
||||
#[strum(props(fallback = "%1$s sent a message from another device."))]
|
||||
ChatProtectionDisabled = 171,
|
||||
|
||||
@@ -1031,8 +1029,8 @@ pub(crate) async fn error_no_network(context: &Context) -> String {
|
||||
translated(context, StockMessage::ErrorNoNetwork).await
|
||||
}
|
||||
|
||||
/// Stock string: `Messages are guaranteed to be end-to-end encrypted from now on.`
|
||||
pub(crate) async fn chat_protection_enabled(context: &Context) -> String {
|
||||
/// Stock string: `Messages are end-to-end encrypted.`
|
||||
pub(crate) async fn messages_e2e_encrypted(context: &Context) -> String {
|
||||
translated(context, StockMessage::ChatProtectionEnabled).await
|
||||
}
|
||||
|
||||
@@ -1303,7 +1301,7 @@ impl Context {
|
||||
"[Error] No contact_id given".to_string()
|
||||
}
|
||||
}
|
||||
ProtectionStatus::Protected => chat_protection_enabled(self).await,
|
||||
ProtectionStatus::Protected => messages_e2e_encrypted(self).await,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,10 @@ use crate::securejoin::{get_securejoin_qr, join_securejoin};
|
||||
use crate::stock_str::StockStrings;
|
||||
use crate::tools::time;
|
||||
|
||||
/// The number of info messages added to new e2ee chats.
|
||||
/// Currently this is "End-to-end encryption available", string `E2eAvailable`.
|
||||
pub const E2EE_INFO_MSGS: usize = 1;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const AVATAR_900x900_BYTES: &[u8] = include_bytes!("../test-data/image/avatar900x900.png");
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@ use crate::mimeparser::SystemMessage;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::securejoin::{get_securejoin_qr, join_securejoin};
|
||||
use crate::stock_str;
|
||||
use crate::test_utils::{TestContext, TestContextManager, get_chat_msg, mark_as_verified};
|
||||
use crate::test_utils::{
|
||||
E2EE_INFO_MSGS, TestContext, TestContextManager, get_chat_msg, mark_as_verified,
|
||||
};
|
||||
use crate::tools::SystemTime;
|
||||
use crate::{e2ee, message};
|
||||
|
||||
@@ -132,7 +134,7 @@ async fn test_create_verified_oneonone_chat() -> Result<()> {
|
||||
assert!(chat.is_protected());
|
||||
|
||||
let msg = get_chat_msg(&alice, chat.id, 0, 1).await;
|
||||
let expected_text = stock_str::chat_protection_enabled(&alice).await;
|
||||
let expected_text = stock_str::messages_e2e_encrypted(&alice).await;
|
||||
assert_eq!(msg.text, expected_text);
|
||||
}
|
||||
|
||||
@@ -142,7 +144,7 @@ async fn test_create_verified_oneonone_chat() -> Result<()> {
|
||||
assert!(chat.is_protected());
|
||||
|
||||
let msg0 = get_chat_msg(&fiona, chat.id, 0, 1).await;
|
||||
let expected_text = stock_str::chat_protection_enabled(&fiona).await;
|
||||
let expected_text = stock_str::messages_e2e_encrypted(&fiona).await;
|
||||
assert_eq!(msg0.text, expected_text);
|
||||
}
|
||||
|
||||
@@ -162,7 +164,7 @@ async fn test_create_verified_oneonone_chat() -> Result<()> {
|
||||
let chat = alice.get_chat(&fiona_new).await;
|
||||
assert!(!chat.is_protected());
|
||||
|
||||
let msg = get_chat_msg(&alice, chat.id, 0, 1).await;
|
||||
let msg = get_chat_msg(&alice, chat.id, 1, E2EE_INFO_MSGS + 1).await;
|
||||
assert_eq!(msg.text, "I have a new device");
|
||||
|
||||
// After recreating the chat, it should still be unprotected
|
||||
@@ -268,7 +270,7 @@ async fn test_degrade_verified_oneonone_chat() -> Result<()> {
|
||||
.await?;
|
||||
|
||||
let msg0 = get_chat_msg(&alice, alice_chat.id, 0, 1).await;
|
||||
let enabled = stock_str::chat_protection_enabled(&alice).await;
|
||||
let enabled = stock_str::messages_e2e_encrypted(&alice).await;
|
||||
assert_eq!(msg0.text, enabled);
|
||||
assert_eq!(msg0.param.get_cmd(), SystemMessage::ChatProtectionEnabled);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::config::Config;
|
||||
use crate::download::DownloadState;
|
||||
use crate::ephemeral;
|
||||
use crate::receive_imf::{receive_imf, receive_imf_from_inbox};
|
||||
use crate::test_utils::{TestContext, TestContextManager};
|
||||
use crate::test_utils::{E2EE_INFO_MSGS, TestContext, TestContextManager};
|
||||
use crate::tools::{self, SystemTime};
|
||||
use crate::{message, sql};
|
||||
|
||||
@@ -250,7 +250,7 @@ async fn test_resend_webxdc_instance_and_info() -> Result<()> {
|
||||
);
|
||||
let bob_grp = bob_instance.chat_id;
|
||||
assert_eq!(bob.get_last_msg_in(bob_grp).await.id, bob_instance.id);
|
||||
assert_eq!(bob_grp.get_msg_cnt(&bob).await?, 1);
|
||||
assert_eq!(bob_grp.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -869,14 +869,14 @@ async fn test_send_big_webxdc_status_update() -> Result<()> {
|
||||
let sent2 = &alice.pop_sent_msg().await;
|
||||
let alice_update = sent2.load_from_db().await;
|
||||
assert_eq!(alice_update.text, BODY_DESCR.to_string());
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, 1);
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, E2EE_INFO_MSGS + 1);
|
||||
|
||||
// Bob receives the instance.
|
||||
let bob_instance = bob.recv_msg(sent1).await;
|
||||
let bob_chat_id = bob_instance.chat_id;
|
||||
assert_eq!(bob_instance.rfc724_mid, alice_instance.rfc724_mid);
|
||||
assert_eq!(bob_instance.viewtype, Viewtype::Webxdc);
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 1);
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 1);
|
||||
|
||||
// Bob receives the status updates.
|
||||
bob.recv_msg_trash(sent2).await;
|
||||
@@ -896,7 +896,7 @@ async fn test_send_big_webxdc_status_update() -> Result<()> {
|
||||
r#"[{"payload":{"foo":"bar2"},"serial":2,"max_serial":3},
|
||||
{"payload":{"foo":"bar3"},"serial":3,"max_serial":3}]"#
|
||||
);
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 1);
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1485,7 +1485,7 @@ async fn test_webxdc_info_msg() -> Result<()> {
|
||||
let alice_chat = alice.create_chat(&bob).await;
|
||||
let alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?;
|
||||
let sent1 = &alice.pop_sent_msg().await;
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, 1);
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, E2EE_INFO_MSGS + 1);
|
||||
|
||||
alice
|
||||
.send_webxdc_status_update(
|
||||
@@ -1495,7 +1495,7 @@ async fn test_webxdc_info_msg() -> Result<()> {
|
||||
.await?;
|
||||
alice.flush_status_updates().await?;
|
||||
let sent2 = &alice.pop_sent_msg().await;
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, 2);
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, E2EE_INFO_MSGS + 2);
|
||||
let info_msg = alice.get_last_msg().await;
|
||||
assert!(info_msg.is_info());
|
||||
assert_eq!(info_msg.get_info_type(), SystemMessage::WebxdcInfoMessage);
|
||||
@@ -1517,7 +1517,7 @@ async fn test_webxdc_info_msg() -> Result<()> {
|
||||
let bob_instance = bob.recv_msg(sent1).await;
|
||||
let bob_chat_id = bob_instance.chat_id;
|
||||
bob.recv_msg_trash(sent2).await;
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 2);
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 2);
|
||||
let info_msg = bob.get_last_msg().await;
|
||||
assert!(info_msg.is_info());
|
||||
assert_eq!(info_msg.get_info_type(), SystemMessage::WebxdcInfoMessage);
|
||||
@@ -1536,7 +1536,10 @@ async fn test_webxdc_info_msg() -> Result<()> {
|
||||
let alice2_instance = alice2.recv_msg(sent1).await;
|
||||
let alice2_chat_id = alice2_instance.chat_id;
|
||||
alice2.recv_msg_trash(sent2).await;
|
||||
assert_eq!(alice2_chat_id.get_msg_cnt(&alice2).await?, 2);
|
||||
assert_eq!(
|
||||
alice2_chat_id.get_msg_cnt(&alice2).await?,
|
||||
E2EE_INFO_MSGS + 2
|
||||
);
|
||||
let info_msg = alice2.get_last_msg().await;
|
||||
assert!(info_msg.is_info());
|
||||
assert_eq!(info_msg.get_info_type(), SystemMessage::WebxdcInfoMessage);
|
||||
@@ -1572,13 +1575,13 @@ async fn test_webxdc_info_msg_cleanup_series() -> Result<()> {
|
||||
.await?;
|
||||
alice.flush_status_updates().await?;
|
||||
let sent2 = &alice.pop_sent_msg().await;
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, 2);
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, E2EE_INFO_MSGS + 2);
|
||||
alice
|
||||
.send_webxdc_status_update(alice_instance.id, r#"{"info":"i2", "payload":2}"#)
|
||||
.await?;
|
||||
alice.flush_status_updates().await?;
|
||||
let sent3 = &alice.pop_sent_msg().await;
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, 2);
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(&alice).await?, E2EE_INFO_MSGS + 2);
|
||||
let info_msg = alice.get_last_msg().await;
|
||||
assert_eq!(info_msg.get_text(), "i2");
|
||||
|
||||
@@ -1586,9 +1589,9 @@ async fn test_webxdc_info_msg_cleanup_series() -> Result<()> {
|
||||
let bob_instance = bob.recv_msg(sent1).await;
|
||||
let bob_chat_id = bob_instance.chat_id;
|
||||
bob.recv_msg_trash(sent2).await;
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 2);
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 2);
|
||||
bob.recv_msg_trash(sent3).await;
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 2);
|
||||
assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, E2EE_INFO_MSGS + 2);
|
||||
let info_msg = bob.get_last_msg().await;
|
||||
assert_eq!(info_msg.get_text(), "i2");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user