Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ignore encryption preferences #6612

Merged
merged 2 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions deltachat-rpc-client/tests/test_something.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,3 +710,28 @@ def test_configured_imap_certificate_checks(acfactory):
# Core 1.142.4, 1.142.5 and 1.142.6 saved this value due to bug.
# This test is a regression test to prevent this happening again.
assert configured_certificate_checks != "0"


def test_no_old_msg_is_fresh(acfactory):
ac1, ac2 = acfactory.get_online_accounts(2)
ac1_clone = ac1.clone()
ac1_clone.start_io()

ac1.create_chat(ac2)
ac1_clone_chat = ac1_clone.create_chat(ac2)

ac1.get_device_chat().mark_noticed()

logging.info("Send a first message from ac2 to ac1 and check that it's 'fresh'")
first_msg = ac2.create_chat(ac1).send_text("Hi")
ac1.wait_for_incoming_msg_event()
assert ac1.create_chat(ac2).get_fresh_message_count() == 1
assert len(list(ac1.get_fresh_messages())) == 1

logging.info("Send a message from ac1_clone to ac2 and check that ac1 marks the first message as 'noticed'")
ac1_clone_chat.send_text("Hi back")
ev = ac1.wait_for_msgs_noticed_event()

assert ev.chat_id == first_msg.get_snapshot().chat_id
assert ac1.create_chat(ac2).get_fresh_message_count() == 0
assert len(list(ac1.get_fresh_messages())) == 0
2 changes: 0 additions & 2 deletions python/src/deltachat/testplugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,8 +423,6 @@ def get_next_liveconfig(self):
where we can make valid SMTP and IMAP connections with.
"""
configdict = next(self._liveconfig_producer).copy()
if "e2ee_enabled" not in configdict:
configdict["e2ee_enabled"] = "1"

if self.pytestconfig.getoption("--strict-tls"):
# Enable strict certificate checks for online accounts
Expand Down
198 changes: 0 additions & 198 deletions python/tests/test_1_online.py
Original file line number Diff line number Diff line change
Expand Up @@ -919,64 +919,6 @@ def test_gossip_optimization(acfactory, lp):
assert gossiped_timestamp == int(msg.time_sent.timestamp())


def test_gossip_encryption_preference(acfactory, lp):
"""Test that encryption preference of group members is gossiped to new members.
This is a Delta Chat extension to Autocrypt 1.1.0, which Autocrypt-Gossip headers
SHOULD NOT contain encryption preference.
"""
ac1, ac2, ac3 = acfactory.get_online_accounts(3)

lp.sec("ac1 learns that ac2 prefers encryption")
ac1.create_chat(ac2)
msg = ac2.create_chat(ac1).send_text("first message")
msg = ac1._evtracker.wait_next_incoming_message()
assert msg.text == "first message"
assert not msg.is_encrypted()
res = "End-to-end encryption preferred:\n{}".format(ac2.get_config("addr"))
assert msg.chat.get_encryption_info() == res
lp.sec("ac2 learns that ac3 prefers encryption")
ac2.create_chat(ac3)
msg = ac3.create_chat(ac2).send_text("I prefer encryption")
msg = ac2._evtracker.wait_next_incoming_message()
assert msg.text == "I prefer encryption"
assert not msg.is_encrypted()

lp.sec("ac3 does not know that ac1 prefers encryption")
ac1.create_chat(ac3)
chat = ac3.create_chat(ac1)
res = "No encryption:\n{}".format(ac1.get_config("addr"))
assert chat.get_encryption_info() == res
msg = chat.send_text("not encrypted")
msg = ac1._evtracker.wait_next_incoming_message()
assert msg.text == "not encrypted"
assert not msg.is_encrypted()

lp.sec("ac1 creates a group chat with ac2")
group_chat = ac1.create_group_chat("hello")
group_chat.add_contact(ac2)
encryption_info = group_chat.get_encryption_info()
res = "End-to-end encryption preferred:\n{}".format(ac2.get_config("addr"))
assert encryption_info == res
msg = group_chat.send_text("hi")

msg = ac2._evtracker.wait_next_incoming_message()
assert msg.is_encrypted()
assert msg.text == "hi"

lp.sec("ac2 adds ac3 to the group")
msg.chat.add_contact(ac3)
assert msg.is_encrypted()

lp.sec("ac3 learns that ac1 prefers encryption")
msg = ac3._evtracker.wait_next_incoming_message()
encryption_info = msg.chat.get_encryption_info().splitlines()
assert encryption_info[0] == "End-to-end encryption preferred:"
assert ac1.get_config("addr") in encryption_info[1:]
assert ac2.get_config("addr") in encryption_info[1:]
msg = chat.send_text("encrypted")
assert msg.is_encrypted()


def test_send_first_message_as_long_unicode_with_cr(acfactory, lp):
ac1, ac2 = acfactory.get_online_accounts(2)

Expand Down Expand Up @@ -1167,93 +1109,6 @@ def test_dont_show_emails(acfactory, lp):
assert len(msg.chat.get_messages()) == 3


def test_no_old_msg_is_fresh(acfactory, lp):
ac1 = acfactory.new_online_configuring_account()
ac2 = acfactory.new_online_configuring_account()
ac1_clone = acfactory.new_online_configuring_account(cloned_from=ac1)
acfactory.bring_accounts_online()

ac1.set_config("e2ee_enabled", "0")
ac1_clone.set_config("e2ee_enabled", "0")
ac2.set_config("e2ee_enabled", "0")

ac1_clone.set_config("bcc_self", "1")

ac1.create_chat(ac2)
ac1_clone.create_chat(ac2)

ac1.get_device_chat().mark_noticed()

lp.sec("Send a first message from ac2 to ac1 and check that it's 'fresh'")
first_msg_id = ac2.create_chat(ac1).send_text("Hi")
ac1._evtracker.wait_next_incoming_message()
assert ac1.create_chat(ac2).count_fresh_messages() == 1
assert len(list(ac1.get_fresh_messages())) == 1

lp.sec("Send a message from ac1_clone to ac2 and check that ac1 marks the first message as 'noticed'")
ac1_clone.create_chat(ac2).send_text("Hi back")
ev = ac1._evtracker.get_matching("DC_EVENT_MSGS_NOTICED")

assert ev.data1 == first_msg_id.chat.id
assert ac1.create_chat(ac2).count_fresh_messages() == 0
assert len(list(ac1.get_fresh_messages())) == 0


def test_prefer_encrypt(acfactory, lp):
"""Test quorum rule for encryption preference in 1:1 and group chat."""
ac1 = acfactory.new_online_configuring_account(fix_is_chatmail=True)
ac2 = acfactory.new_online_configuring_account(fix_is_chatmail=True)
ac3 = acfactory.new_online_configuring_account(fix_is_chatmail=True)
acfactory.bring_accounts_online()
ac1.set_config("e2ee_enabled", "0")
ac2.set_config("e2ee_enabled", "1")
ac3.set_config("e2ee_enabled", "0")

# Make sure we do not send a copy to ourselves. This is to
# test that we count own preference even when we are not in
# the recipient list.
ac1.set_config("bcc_self", "0")
ac2.set_config("bcc_self", "0")
ac3.set_config("bcc_self", "0")

acfactory.introduce_each_other([ac1, ac2, ac3])

lp.sec("ac1: sending message to ac2")
chat1 = ac1.create_chat(ac2)
msg1 = chat1.send_text("message1")
assert not msg1.is_encrypted()
ac2._evtracker.wait_next_incoming_message()

lp.sec("ac2: sending message to ac1")
chat2 = ac2.create_chat(ac1)
msg2 = chat2.send_text("message2")
# Own preference is `Mutual` and we have the peer's key.
assert msg2.is_encrypted()
ac1._evtracker.wait_next_incoming_message()

lp.sec("ac1: sending message to group chat with ac2 and ac3")
group = ac1.create_group_chat("hello")
group.add_contact(ac2)
group.add_contact(ac3)
msg3 = group.send_text("message3")
assert not msg3.is_encrypted()
ac2._evtracker.wait_next_incoming_message()
ac3._evtracker.wait_next_incoming_message()

lp.sec("ac3: start preferring encryption and inform ac1")
ac3.set_config("e2ee_enabled", "1")
chat3 = ac3.create_chat(ac1)
msg4 = chat3.send_text("message4")
# Own preference is `Mutual` and we have the peer's key.
assert msg4.is_encrypted()
ac1._evtracker.wait_next_incoming_message()

lp.sec("ac1: sending another message to group chat with ac2 and ac3")
msg5 = group.send_text("message5")
# Majority prefers encryption now
assert msg5.is_encrypted()


def test_bot(acfactory, lp):
"""Test that bot messages can be identified as such"""
ac1, ac2 = acfactory.get_online_accounts(2)
Expand Down Expand Up @@ -1282,59 +1137,6 @@ def test_bot(acfactory, lp):
assert msg_in.is_bot()


def test_quote_encrypted(acfactory, lp):
"""Test that replies to encrypted messages with quotes are encrypted."""
ac1, ac2 = acfactory.get_online_accounts(2)

lp.sec("ac1: create chat with ac2")
chat = ac1.create_chat(ac2)

lp.sec("sending text message from ac1 to ac2")
msg1 = chat.send_text("message1")
assert not msg1.is_encrypted()

lp.sec("wait for ac2 to receive message")
msg2 = ac2._evtracker.wait_next_incoming_message()
assert msg2.text == "message1"
assert not msg2.is_encrypted()

lp.sec("create new chat with contact and send back (encrypted) message")
msg2.create_chat().send_text("message-back")

lp.sec("wait for ac1 to receive message")
msg3 = ac1._evtracker.wait_next_incoming_message()
assert msg3.text == "message-back"
assert msg3.is_encrypted()

lp.sec("ac1: e2ee_enabled=0 and see if reply is encrypted")
print("ac1: e2ee_enabled={}".format(ac1.get_config("e2ee_enabled")))
print("ac2: e2ee_enabled={}".format(ac2.get_config("e2ee_enabled")))
ac1.set_config("e2ee_enabled", "0")

for quoted_msg in msg1, msg3:
# Save the draft with a quote.
msg_draft = Message.new_empty(ac1, "text")
msg_draft.set_text("message reply")
msg_draft.quote = quoted_msg
chat.set_draft(msg_draft)

# Get the draft and send it.
msg_draft = chat.get_draft()
chat.send_msg(msg_draft)

chat.set_draft(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()
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


def test_quote_attachment(tmp_path, acfactory, lp):
"""Test that replies with an attachment and a quote are received correctly."""
ac1, ac2 = acfactory.get_online_accounts(2)
Expand Down
21 changes: 6 additions & 15 deletions src/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1313,8 +1313,7 @@ impl ChatId {
///
/// To get more verbose summary for a contact, including its key fingerprint, use [`Contact::get_encrinfo`].
pub async fn get_encryption_info(self, context: &Context) -> Result<String> {
let mut ret_mutual = String::new();
let mut ret_nopreference = String::new();
let mut ret_available = String::new();
let mut ret_reset = String::new();

for contact_id in get_chat_contacts(context, self)
Expand All @@ -1330,8 +1329,9 @@ impl ChatId {
.filter(|peerstate| peerstate.peek_key(false).is_some())
.map(|peerstate| peerstate.prefer_encrypt)
{
Some(EncryptPreference::Mutual) => ret_mutual += &format!("{addr}\n"),
Some(EncryptPreference::NoPreference) => ret_nopreference += &format!("{addr}\n"),
Some(EncryptPreference::Mutual) | Some(EncryptPreference::NoPreference) => {
ret_available += &format!("{addr}\n")
}
Some(EncryptPreference::Reset) | None => ret_reset += &format!("{addr}\n"),
};
}
Expand All @@ -1343,23 +1343,14 @@ impl ChatId {
ret.push('\n');
ret += &ret_reset;
}
if !ret_nopreference.is_empty() {
if !ret_available.is_empty() {
if !ret.is_empty() {
ret.push('\n');
}
ret += &stock_str::e2e_available(context).await;
ret.push(':');
ret.push('\n');
ret += &ret_nopreference;
}
if !ret_mutual.is_empty() {
if !ret.is_empty() {
ret.push('\n');
}
ret += &stock_str::e2e_preferred(context).await;
ret.push(':');
ret.push('\n');
ret += &ret_mutual;
ret += &ret_available;
}

Ok(ret.trim().to_string())
Expand Down
10 changes: 1 addition & 9 deletions src/chat/chat_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,6 @@ async fn test_member_add_remove() -> Result<()> {
let alice = tcm.alice().await;
let bob = tcm.bob().await;

// Disable encryption so we can inspect raw message contents.
alice.set_config(Config::E2eeEnabled, Some("0")).await?;
bob.set_config(Config::E2eeEnabled, Some("0")).await?;

// Create contact for Bob on the Alice side with name "robert".
let alice_bob_contact_id = Contact::create(&alice, "robert", "[email protected]").await?;

Expand Down Expand Up @@ -373,9 +369,6 @@ async fn test_parallel_member_remove() -> Result<()> {
let alice = tcm.alice().await;
let bob = tcm.bob().await;

alice.set_config(Config::E2eeEnabled, Some("0")).await?;
bob.set_config(Config::E2eeEnabled, Some("0")).await?;

let alice_bob_contact_id = Contact::create(&alice, "Bob", "[email protected]").await?;
let alice_fiona_contact_id = Contact::create(&alice, "Fiona", "[email protected]").await?;
let alice_claire_contact_id = Contact::create(&alice, "Claire", "[email protected]").await?;
Expand Down Expand Up @@ -2677,11 +2670,10 @@ async fn test_chat_get_encryption_info() -> Result<()> {
"No encryption:\n\
[email protected]\n\
\n\
End-to-end encryption preferred:\n\
End-to-end encryption available:\n\
[email protected]"
);

bob.set_config(Config::E2eeEnabled, Some("0")).await?;
send_text_msg(&bob, direct_chat.id, "Hello!".to_string()).await?;
alice.recv_msg(&bob.pop_sent_msg().await).await;

Expand Down
2 changes: 1 addition & 1 deletion src/config/config_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ async fn test_set_config_bool() -> Result<()> {
let t = TestContext::new().await;

// We need some config that defaults to true
let c = Config::E2eeEnabled;
let c = Config::MdnsEnabled;
assert_eq!(t.get_config_bool(c).await?, true);
t.set_config_bool(c, false).await?;
assert_eq!(t.get_config_bool(c).await?, false);
Expand Down
1 change: 0 additions & 1 deletion src/configure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,6 @@ async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result<Configure
ctx.set_config(Config::MvboxMove, Some("0")).await?;
ctx.set_config(Config::OnlyFetchMvbox, None).await?;
ctx.set_config(Config::ShowEmails, None).await?;
ctx.set_config(Config::E2eeEnabled, Some("1")).await?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if encryption preference is still sent in the Autocrypt header, can't this lead to other Autocrypt-capable MUA or old Delta Chat sending messages unencrypted?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume that it's enabled anyway, so, no need to enable it again?

}

let create_mvbox = !is_chatmail;
Expand Down
Loading
Loading