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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
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
166 changes: 0 additions & 166 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,61 +1109,6 @@ def test_dont_show_emails(acfactory, lp):
assert len(msg.chat.get_messages()) == 3


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 @@ -1250,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
72 changes: 4 additions & 68 deletions src/e2ee.rs
Copy link
Collaborator

Choose a reason for hiding this comment

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

FTR, the important semantic change is in this file here, everything else is just tests

Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,13 @@ impl EncryptHelper {
peerstates: &[(Option<Peerstate>, String)],
) -> Result<bool> {
let is_chatmail = context.is_chatmail().await?;
let mut prefer_encrypt_count = if self.prefer_encrypt == EncryptPreference::Mutual {
1
} else {
0
};
let mut prefer_encrypt_count = 1;
for (peerstate, addr) in peerstates {
match peerstate {
Some(peerstate) => {
let prefer_encrypt = peerstate.prefer_encrypt;
info!(context, "Peerstate for {addr:?} is {prefer_encrypt}.");
if match peerstate.prefer_encrypt {
EncryptPreference::NoPreference | EncryptPreference::Reset => {
(peerstate.prefer_encrypt != EncryptPreference::Reset || is_chatmail)
&& self.prefer_encrypt == EncryptPreference::Mutual
}
EncryptPreference::Mutual => true,
EncryptPreference::Reset => is_chatmail,
EncryptPreference::NoPreference | EncryptPreference::Mutual => true,
} {
prefer_encrypt_count += 1;
}
Expand Down Expand Up @@ -176,6 +167,7 @@ pub async fn ensure_secret_key_exists(context: &Context) -> Result<()> {
mod tests {
use super::*;
use crate::chat::send_text_msg;
use crate::config::Config;
use crate::key::DcKey;
use crate::message::{Message, Viewtype};
use crate::param::Param;
Expand Down Expand Up @@ -329,7 +321,6 @@ Sent with my Delta Chat Messenger: https://delta.chat";
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_should_encrypt() -> Result<()> {
let t = TestContext::new_alice().await;
assert!(t.get_config_bool(Config::E2eeEnabled).await?);
let encrypt_helper = EncryptHelper::new(&t).await.unwrap();

let ps = new_peerstates(EncryptPreference::NoPreference);
Expand All @@ -352,61 +343,6 @@ Sent with my Delta Chat Messenger: https://delta.chat";
Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_should_encrypt_e2ee_disabled() -> Result<()> {
let t = &TestContext::new_alice().await;
t.set_config_bool(Config::E2eeEnabled, false).await?;
let encrypt_helper = EncryptHelper::new(t).await.unwrap();

let ps = new_peerstates(EncryptPreference::NoPreference);
assert!(!encrypt_helper.should_encrypt(t, false, &ps).await?);

let ps = new_peerstates(EncryptPreference::Reset);
assert!(encrypt_helper.should_encrypt(t, true, &ps).await?);

let mut ps = new_peerstates(EncryptPreference::Mutual);
// Own preference is `NoPreference` and there's no majority with `Mutual`.
assert!(!encrypt_helper.should_encrypt(t, false, &ps).await?);
// Now the majority wants to encrypt. Let's encrypt, anyway there are other cases when we
// can't send unencrypted, e.g. protected groups.
ps.push(ps[0].clone());
assert!(encrypt_helper.should_encrypt(t, false, &ps).await?);

// Test with missing peerstate.
let ps = vec![(None, "[email protected]".to_string())];
assert!(encrypt_helper.should_encrypt(t, true, &ps).await.is_err());
Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_chatmail_prefers_to_encrypt() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
bob.set_config_bool(Config::IsChatmail, true).await?;

let bob_chat_id = tcm
.send_recv_accept(alice, bob, "Hello from DC")
.await
.chat_id;
receive_imf(
bob,
b"From: [email protected]\n\
To: [email protected]\n\
Message-ID: <[email protected]>\n\
Date: Sun, 22 Mar 3000 22:37:58 +0000\n\
\n\
Hello from another MUA\n",
false,
)
.await?;
send_text_msg(bob, bob_chat_id, "hi".to_string()).await?;
let sent_msg = bob.pop_sent_msg().await;
let msg = Message::load_from_db(bob, sent_msg.sender_msg_id).await?;
assert!(msg.get_showpadlock());
Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_chatmail_can_send_unencrypted() -> Result<()> {
let mut tcm = TestContextManager::new();
Expand Down
Loading
Loading