mirror of
https://github.com/chatmail/core.git
synced 2026-05-07 17:06:35 +03:00
fix(peerstate): encryption-not-available
Add a test for failing e2e encryption and some info statement to hunt where the e2e encryption failure comes from, as well as fix the issue. Closes #233
This commit is contained in:
committed by
Friedel Ziegelmayer
parent
4d8d5f4e1e
commit
be605d8ea5
@@ -120,6 +120,8 @@ def acfactory(pytestconfig, tmpdir, request):
|
|||||||
pytest.skip("specify a --liveconfig file to run tests with real accounts")
|
pytest.skip("specify a --liveconfig file to run tests with real accounts")
|
||||||
self.live_count += 1
|
self.live_count += 1
|
||||||
configdict = self.configlist.pop(0)
|
configdict = self.configlist.pop(0)
|
||||||
|
if "e2ee_enabled" not in configdict:
|
||||||
|
configdict["e2ee_enabled"] = "1"
|
||||||
tmpdb = tmpdir.join("livedb%d" % self.live_count)
|
tmpdb = tmpdir.join("livedb%d" % self.live_count)
|
||||||
ac = Account(tmpdb.strpath, logid="ac{}".format(self.live_count))
|
ac = Account(tmpdb.strpath, logid="ac{}".format(self.live_count))
|
||||||
ac._evlogger.init_time = self.init_time
|
ac._evlogger.init_time = self.init_time
|
||||||
|
|||||||
@@ -427,6 +427,37 @@ class TestOnlineAccount:
|
|||||||
lp.step("2")
|
lp.step("2")
|
||||||
assert msg_out.is_out_mdn_received()
|
assert msg_out.is_out_mdn_received()
|
||||||
|
|
||||||
|
def test_send_and_receive_will_encrypt_decrypt(self, acfactory, lp):
|
||||||
|
lp.sec("starting accounts, waiting for configuration")
|
||||||
|
ac1 = acfactory.get_online_configuring_account()
|
||||||
|
ac2 = acfactory.get_online_configuring_account()
|
||||||
|
c2 = ac1.create_contact(email=ac2.get_config("addr"))
|
||||||
|
chat = ac1.create_chat_by_contact(c2)
|
||||||
|
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||||
|
|
||||||
|
wait_configuration_progress(ac1, 1000)
|
||||||
|
wait_configuration_progress(ac2, 1000)
|
||||||
|
|
||||||
|
lp.sec("sending text message from ac1 to ac2")
|
||||||
|
msg_out = chat.send_text("message1")
|
||||||
|
|
||||||
|
lp.sec("wait for ac2 to receive message")
|
||||||
|
ev = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||||
|
assert ev[2] == msg_out.id
|
||||||
|
msg_in = ac2.get_message_by_id(msg_out.id)
|
||||||
|
assert msg_in.text == "message1"
|
||||||
|
|
||||||
|
lp.sec("create new chat with contact and send back (encrypted) message")
|
||||||
|
chat2b = ac2.create_chat_by_message(msg_in)
|
||||||
|
chat2b.send_text("message-back")
|
||||||
|
|
||||||
|
lp.sec("wait for ac1 to receive message")
|
||||||
|
ev = ac1._evlogger.get_matching("DC_EVENT_INCOMING_MSG")
|
||||||
|
assert ev[1] == chat.id
|
||||||
|
assert ev[2] > msg_out.id
|
||||||
|
msg_back = ac1.get_message_by_id(ev[2])
|
||||||
|
assert msg_back.text == "message-back"
|
||||||
|
|
||||||
def test_saved_mime_on_received_message(self, acfactory, lp):
|
def test_saved_mime_on_received_message(self, acfactory, lp):
|
||||||
lp.sec("starting accounts, waiting for configuration")
|
lp.sec("starting accounts, waiting for configuration")
|
||||||
ac1 = acfactory.get_online_configuring_account()
|
ac1 = acfactory.get_online_configuring_account()
|
||||||
|
|||||||
@@ -115,11 +115,22 @@ pub unsafe fn dc_e2ee_encrypt(
|
|||||||
|| 0 != e2ee_guaranteed)
|
|| 0 != e2ee_guaranteed)
|
||||||
{
|
{
|
||||||
let peerstate = peerstate.unwrap();
|
let peerstate = peerstate.unwrap();
|
||||||
|
info!(
|
||||||
|
context,
|
||||||
|
0, "dc_e2ee_encrypt {} has peerstate", recipient_addr
|
||||||
|
);
|
||||||
if let Some(key) = peerstate.peek_key(min_verified as usize) {
|
if let Some(key) = peerstate.peek_key(min_verified as usize) {
|
||||||
keyring.add_owned(key.clone());
|
keyring.add_owned(key.clone());
|
||||||
peerstates.push(peerstate);
|
peerstates.push(peerstate);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
info!(
|
||||||
|
context,
|
||||||
|
0,
|
||||||
|
"dc_e2ee_encrypt {} HAS NO peerstate {}",
|
||||||
|
recipient_addr,
|
||||||
|
peerstate.is_some()
|
||||||
|
);
|
||||||
do_encrypt = 0i32;
|
do_encrypt = 0i32;
|
||||||
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
|
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
|
||||||
break;
|
break;
|
||||||
@@ -574,7 +585,7 @@ pub unsafe fn dc_e2ee_decrypt(
|
|||||||
}
|
}
|
||||||
} else if let Some(ref header) = autocryptheader {
|
} else if let Some(ref header) = autocryptheader {
|
||||||
let p = Peerstate::from_header(context, header, message_time);
|
let p = Peerstate::from_header(context, header, message_time);
|
||||||
p.save_to_db(&context.sql, true);
|
assert!(p.save_to_db(&context.sql, true));
|
||||||
peerstate = Some(p);
|
peerstate = Some(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,7 +166,6 @@ impl<'a> Peerstate<'a> {
|
|||||||
|
|
||||||
pub fn from_addr(context: &'a Context, _sql: &Sql, addr: &str) -> Option<Self> {
|
pub fn from_addr(context: &'a Context, _sql: &Sql, addr: &str) -> Option<Self> {
|
||||||
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;";
|
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;";
|
||||||
|
|
||||||
Self::from_stmt(context, query, &[addr])
|
Self::from_stmt(context, query, &[addr])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,6 +190,11 @@ impl<'a> Peerstate<'a> {
|
|||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
.query_row(query, params, |row| {
|
.query_row(query, params, |row| {
|
||||||
|
/* all the above queries start with this: SELECT
|
||||||
|
addr, last_seen, last_seen_autocrypt, prefer_encrypted,
|
||||||
|
public_key, gossip_timestamp, gossip_key, public_key_fingerprint,
|
||||||
|
gossip_key_fingerprint, verified_key, verified_key_fingerprint
|
||||||
|
*/
|
||||||
let mut res = Self::new(context);
|
let mut res = Self::new(context);
|
||||||
|
|
||||||
res.addr = Some(row.get(0)?);
|
res.addr = Some(row.get(0)?);
|
||||||
@@ -198,13 +202,34 @@ impl<'a> Peerstate<'a> {
|
|||||||
res.last_seen_autocrypt = row.get(2)?;
|
res.last_seen_autocrypt = row.get(2)?;
|
||||||
res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default();
|
res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default();
|
||||||
res.gossip_timestamp = row.get(5)?;
|
res.gossip_timestamp = row.get(5)?;
|
||||||
let pkf: String = row.get(7)?;
|
|
||||||
res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) };
|
|
||||||
let gkf: String = row.get(8)?;
|
|
||||||
res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) };
|
|
||||||
let vkf: String = row.get(10)?;
|
|
||||||
res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) };
|
|
||||||
|
|
||||||
|
res.public_key_fingerprint = row.get(7)?;
|
||||||
|
if res
|
||||||
|
.public_key_fingerprint
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.is_empty())
|
||||||
|
.unwrap_or_default()
|
||||||
|
{
|
||||||
|
res.public_key_fingerprint = None;
|
||||||
|
}
|
||||||
|
res.gossip_key_fingerprint = row.get(8)?;
|
||||||
|
if res
|
||||||
|
.gossip_key_fingerprint
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.is_empty())
|
||||||
|
.unwrap_or_default()
|
||||||
|
{
|
||||||
|
res.gossip_key_fingerprint = None;
|
||||||
|
}
|
||||||
|
res.verified_key_fingerprint = row.get(10)?;
|
||||||
|
if res
|
||||||
|
.verified_key_fingerprint
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.is_empty())
|
||||||
|
.unwrap_or_default()
|
||||||
|
{
|
||||||
|
res.verified_key_fingerprint = None;
|
||||||
|
}
|
||||||
res.public_key = row
|
res.public_key = row
|
||||||
.get(4)
|
.get(4)
|
||||||
.ok()
|
.ok()
|
||||||
@@ -217,7 +242,8 @@ impl<'a> Peerstate<'a> {
|
|||||||
.get(9)
|
.get(9)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
|
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
|
||||||
res.verified_key = if vk == res.gossip_key {
|
|
||||||
|
res.verified_key = if vk == res.gossip_key && res.gossip_key.is_some() {
|
||||||
VerifiedKey::Gossip
|
VerifiedKey::Gossip
|
||||||
} else if vk == res.public_key {
|
} else if vk == res.public_key {
|
||||||
VerifiedKey::Public
|
VerifiedKey::Public
|
||||||
@@ -422,6 +448,7 @@ impl<'a> Peerstate<'a> {
|
|||||||
&self.addr,
|
&self.addr,
|
||||||
],
|
],
|
||||||
).is_ok();
|
).is_ok();
|
||||||
|
assert_eq!(success, true);
|
||||||
} else if self.to_save == Some(ToSave::Timestamps) {
|
} else if self.to_save == Some(ToSave::Timestamps) {
|
||||||
success = sql::execute(
|
success = sql::execute(
|
||||||
self.context,
|
self.context,
|
||||||
@@ -498,6 +525,40 @@ mod tests {
|
|||||||
assert_eq!(peerstate, peerstate_new);
|
assert_eq!(peerstate, peerstate_new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_peerstate_with_empty_gossip_key_save_to_db() {
|
||||||
|
let ctx = crate::test_utils::dummy_context();
|
||||||
|
let addr = "hello@mail.com";
|
||||||
|
|
||||||
|
let pub_key = crate::key::Key::from_base64("xsBNBFztUVkBCADYaQl/UOUpRPd32nLRzx8eU0eI+jQEnG+g5anjYA+3oct1rROGl5SygjMULDKdaUy27O3o9Srsti0YjA7uxZnavIqhSopJhFidqY1M1wA9JZa/duucZdNwUGbjGIRsS/4Cjr5+3svscK24hVYub1dvDWXpwUTnj3K6xOEnJdoM+MhCqtSD5+zcJhFc9vyZm9ZTGWUxAhKh0iJTcCD8V6CQ3XZ2z9GruwzZT/FTFovWrz7m3TUI2OdSSHh0eZLRGEoxMCT/vzflAFGAr8ijCaRsEIfqP6FW8uQWnFTqkjxEUCZG6XkeFHB84aj5jqYG/1KCLjL5vEKwfl1tz/WnPhY7ABEBAAHNEDxoZWxsb0BtYWlsLmNvbT7CwIkEEAEIADMCGQEFAlztUVoCGwMECwkIBwYVCAkKCwIDFgIBFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7ijAwf+PTsuawUax9cNPn1bN90H+g9qyHZJMEwKXtUnNaXJxPW3iB7ThhpCiCzsZwP7+l7ArS8tmLeNDw2bENtcf1XCv4wovP2fdXOP3QOUUFX/GdakcTwv7DzC7CO0grB1HtaPhGw/6UX2o2cx2i9xiUf4Givq2MfCbgAW5zloH6WXGPb6yLQYJXxqDIphr4+uZDb+bMAyWHN/DUkAjHrV8nnVki7PMHqzzZpwglalxMX8RGeiGZE39ALJKL/Og87DMFah87/yoxQWGoS7Wqv0XDcCPKoTCPrpk8pOe2KEsq/lz215nefHd4aRpfUX5YCYa8HPvvfPQbGF73uvyQw5w7qjis7ATQRc7VFZAQgAt8ONdnX6KEEQ5Jw6ilJ+LBtY44SP5t0I3eK+goKepgIiKhjGDa+Mntyi4jdhH+HO6kvK5SHMh2sPp4rRO/WKHJwWFySyM1OdyiywhyH0J9R5rBY4vPHsJjf6vSKJdWLWT+ho1fNet2IIC+jVCYli91MAMbRvk6EKVj1nCc+67giOahXEkHt6xxkeCGlOvbw8hxGj1A8+AC1BLms/OR3oc4JMi9O3kq6uG0z9tlUEerac9HVwcjoO1XLe+hJhoT5H+TbnGjPuhuURP3pFiIKHpbRYgUfdSAY0dTObO7t4I5y/drPOrCTnWrBUg2wXAECUhpRKow9/ai2YemLv9KqhhwARAQABwsB2BBgBCAAgBQJc7VFaAhsMFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7jmyggAhs4QzCzIbT2OsAReBxkxtm0AI+g1HZ1KFKof5NDHfgv9C/Qu1I8mKEjlZzA4qFyPmLqntgwJ0RuFy6gLbljZBNCFO7vB478AhYtnWjuKZmA40HUPwcB1hEJ31c42akzfUbioY1TLLepngdsJg7Cm8O+rhI9+1WRA66haJDgFs793SVUDyJh8f9NX50l5zR87/bsV30CFSw0q4OSSy9VI/z+2g5khn1LnuuOrCfFnYIPYtJED1BfkXkosxGlgbzy79VvGmI9d23x4atDK7oBPCzIj+lP8sytJ0u3HOguXi9OgDitKy+Pt1r8gH8frdktMJr5Ts6DW+tIn2vR23KR8aA==", KeyType::Public).unwrap();
|
||||||
|
|
||||||
|
let mut peerstate = Peerstate {
|
||||||
|
context: &ctx.ctx,
|
||||||
|
addr: Some(addr.into()),
|
||||||
|
last_seen: 10,
|
||||||
|
last_seen_autocrypt: 11,
|
||||||
|
prefer_encrypt: EncryptPreference::Mutual,
|
||||||
|
public_key: Some(pub_key.clone()),
|
||||||
|
public_key_fingerprint: Some(pub_key.fingerprint()),
|
||||||
|
gossip_key: None,
|
||||||
|
gossip_timestamp: 12,
|
||||||
|
gossip_key_fingerprint: None,
|
||||||
|
verified_key: VerifiedKey::None,
|
||||||
|
verified_key_fingerprint: None,
|
||||||
|
to_save: Some(ToSave::All),
|
||||||
|
degrade_event: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(peerstate.save_to_db(&ctx.ctx.sql, true), "failed to save");
|
||||||
|
|
||||||
|
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into())
|
||||||
|
.expect("failed to load peerstate from db");
|
||||||
|
|
||||||
|
// clear to_save, as that is not persissted
|
||||||
|
peerstate.to_save = None;
|
||||||
|
assert_eq!(peerstate, peerstate_new);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: don't copy this from stress.rs
|
// TODO: don't copy this from stress.rs
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
struct TestContext {
|
struct TestContext {
|
||||||
|
|||||||
Reference in New Issue
Block a user