mirror of
https://github.com/chatmail/core.git
synced 2026-04-14 03:57:19 +03:00
Compare commits
3 Commits
v2.40.0
...
sk/aliases
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f29d98333f | ||
|
|
2c802516cf | ||
|
|
51276e9320 |
58
src/chat.rs
58
src/chat.rs
@@ -4711,6 +4711,7 @@ impl Context {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::chat;
|
||||
use crate::chatlist::get_archived_cnt;
|
||||
use crate::constants::{DC_GCL_ARCHIVED_ONLY, DC_GCL_NO_SPECIALS};
|
||||
use crate::headerdef::HeaderDef;
|
||||
@@ -7696,4 +7697,61 @@ mod tests {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_reply_with_alias() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
|
||||
// Alice sends a message to Bob
|
||||
let alice_bob_chat = alice.create_chat(&bob).await;
|
||||
let alice_msg = alice.send_text(alice_bob_chat.id, "Hello Bob!").await;
|
||||
let msg = alice_msg.load_from_db().await;
|
||||
bob.recv_msg(&alice_msg).await;
|
||||
|
||||
// Bob replies using an alias email address
|
||||
let alias_email = "bob.alias@example.org";
|
||||
let reply_imf = format!(
|
||||
"From: Bob Alias <{}>\r\n\
|
||||
To: {}\r\n\
|
||||
In-Reply-To: <{}>\r\n\
|
||||
Message-ID: <reply1@alias.example.org>\r\n\
|
||||
\r\n\
|
||||
Hi Alice, this is Bob's alias.",
|
||||
alias_email,
|
||||
alice.get_primary_self_addr().await?,
|
||||
msg.rfc724_mid
|
||||
);
|
||||
|
||||
// Alice receives the raw message
|
||||
let received = receive_imf(&alice, reply_imf.as_bytes(), false)
|
||||
.await?
|
||||
.unwrap();
|
||||
|
||||
// The message should appear in the existing 1:1 chat between Alice and Bob
|
||||
assert_eq!(received.chat_id, alice_bob_chat.id);
|
||||
|
||||
let msg = Message::load_from_db(&alice, received.msg_ids[0]).await?;
|
||||
assert_eq!(msg.text, "Hi Alice, this is Bob's alias.");
|
||||
|
||||
// Alias is displayed in chat
|
||||
assert_eq!(
|
||||
msg.param.get(Param::OverrideSenderDisplayname).unwrap(),
|
||||
"Bob Alias"
|
||||
);
|
||||
|
||||
// Chat remains 1:1
|
||||
let contacts = chat::get_chat_contacts(&alice, alice_bob_chat.id)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(contacts, vec![ContactId::new(10)]);
|
||||
|
||||
// Following messages still go to 1:1 chat
|
||||
let sent = alice.send_text(alice_bob_chat.id, "Hello again!").await;
|
||||
let msg = Message::load_from_db(&alice, sent.sender_msg_id).await?;
|
||||
assert_eq!(msg.chat_id, alice_bob_chat.id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -966,52 +966,55 @@ async fn add_parts(
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the message was sent with verified encryption and set the protection of
|
||||
// the 1:1 chat accordingly.
|
||||
let chat = match is_partial_download.is_none()
|
||||
&& mime_parser.get_header(HeaderDef::SecureJoin).is_none()
|
||||
&& !is_mdn
|
||||
{
|
||||
true => Some(Chat::load_from_db(context, chat_id).await?)
|
||||
.filter(|chat| chat.typ == Chattype::Single),
|
||||
false => None,
|
||||
if let Some(chat_id) = chat_id {
|
||||
let contact = Contact::get_by_id(context, from_id).await?;
|
||||
// Check if the message was sent with verified encryption and set the protection of
|
||||
// the 1:1 chat accordingly.
|
||||
let chat = match is_partial_download.is_none()
|
||||
&& mime_parser.get_header(HeaderDef::SecureJoin).is_none()
|
||||
&& !is_mdn
|
||||
{
|
||||
true => Some(Chat::load_from_db(context, chat_id).await?)
|
||||
.filter(|chat| chat.typ == Chattype::Single),
|
||||
false => None,
|
||||
};
|
||||
if let Some(chat) = chat {
|
||||
debug_assert!(chat.typ == Chattype::Single);
|
||||
let mut new_protection = match verified_encryption {
|
||||
VerifiedEncryption::Verified => ProtectionStatus::Protected,
|
||||
VerifiedEncryption::NotVerified(_) => ProtectionStatus::Unprotected,
|
||||
};
|
||||
if let Some(chat) = chat {
|
||||
debug_assert!(chat.typ == Chattype::Single);
|
||||
let mut new_protection = match verified_encryption {
|
||||
VerifiedEncryption::Verified => ProtectionStatus::Protected,
|
||||
VerifiedEncryption::NotVerified(_) => ProtectionStatus::Unprotected,
|
||||
};
|
||||
|
||||
if chat.protected != ProtectionStatus::Unprotected
|
||||
&& new_protection == ProtectionStatus::Unprotected
|
||||
// `chat.protected` must be maintained regardless of the `Config::VerifiedOneOnOneChats`.
|
||||
// That's why the config is checked here, and not above.
|
||||
&& context.get_config_bool(Config::VerifiedOneOnOneChats).await?
|
||||
{
|
||||
new_protection = ProtectionStatus::ProtectionBroken;
|
||||
}
|
||||
if chat.protected != new_protection {
|
||||
// The message itself will be sorted under the device message since the device
|
||||
// message is `MessageState::InNoticed`, which means that all following
|
||||
// messages are sorted under it.
|
||||
chat_id
|
||||
.set_protection(
|
||||
context,
|
||||
new_protection,
|
||||
mime_parser.timestamp_sent,
|
||||
Some(from_id),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
if let Some(peerstate) = &mime_parser.peerstate {
|
||||
restore_protection = new_protection != ProtectionStatus::Protected
|
||||
&& peerstate.prefer_encrypt == EncryptPreference::Mutual
|
||||
// Check that the contact still has the Autocrypt key same as the
|
||||
// verified key, see also `Peerstate::is_using_verified_key()`.
|
||||
&& contact.is_verified(context).await?;
|
||||
}
|
||||
if chat.protected != ProtectionStatus::Unprotected
|
||||
&& new_protection == ProtectionStatus::Unprotected
|
||||
// `chat.protected` must be maintained regardless of the `Config::VerifiedOneOnOneChats`.
|
||||
// That's why the config is checked here, and not above.
|
||||
&& context.get_config_bool(Config::VerifiedOneOnOneChats).await?
|
||||
{
|
||||
new_protection = ProtectionStatus::ProtectionBroken;
|
||||
}
|
||||
if chat.protected != new_protection {
|
||||
// The message itself will be sorted under the device message since the device
|
||||
// message is `MessageState::InNoticed`, which means that all following
|
||||
// messages are sorted under it.
|
||||
chat_id
|
||||
.set_protection(
|
||||
context,
|
||||
new_protection,
|
||||
mime_parser.timestamp_sent,
|
||||
Some(from_id),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
if let Some(peerstate) = &mime_parser.peerstate {
|
||||
restore_protection = new_protection != ProtectionStatus::Protected
|
||||
&& peerstate.prefer_encrypt == EncryptPreference::Mutual
|
||||
// Check that the contact still has the Autocrypt key same as the
|
||||
// verified key, see also `Peerstate::is_using_verified_key()`.
|
||||
&& contact.is_verified(context).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1805,7 +1808,13 @@ async fn lookup_chat_by_reply(
|
||||
|
||||
// If this was a private message just to self, it was probably a private reply.
|
||||
// It should not go into the group then, but into the private chat.
|
||||
if is_probably_private_reply(context, to_ids, from_id, mime_parser, parent_chat.id).await? {
|
||||
if parent_chat.get_type() != Chattype::Single
|
||||
&& is_probably_private_reply(context, to_ids, from_id, mime_parser, parent_chat.id).await?
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if parent_chat.is_protected() || mime_parser.decrypting_failed {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user