Improve dc_get_contact_encrinfo()

Return error for special IDs. Previously "No encryption." was returned for DC_CONTACT_ID_SELF.

Show "No encryption." if peerstate is reset.

Never talk about transport encryption: it is misleading. Even if TLS is used for client IMAP and SMTP connections, MTA-MTA connection may be unencrypted if MX does not support STARTTLS.

Add a Rust test.
This commit is contained in:
link2xt
2021-02-01 05:37:59 +03:00
committed by link2xt
parent a34cfd56b4
commit fbec12393d
3 changed files with 66 additions and 29 deletions

View File

@@ -5120,9 +5120,7 @@ void dc_event_unref(dc_event_t* event);
/// Used to build the string returned by dc_get_contact_encrinfo(). /// Used to build the string returned by dc_get_contact_encrinfo().
#define DC_STR_E2E_AVAILABLE 25 #define DC_STR_E2E_AVAILABLE 25
/// "Transport-encryption." /// DEPRECATED 2021-02-07
///
/// Used to build the string returned by dc_get_contact_encrinfo().
#define DC_STR_ENCR_TRANSP 27 #define DC_STR_ENCR_TRANSP 27
/// "No encryption." /// "No encryption."

View File

@@ -25,7 +25,6 @@ use crate::message::MessageState;
use crate::mimeparser::AvatarAction; use crate::mimeparser::AvatarAction;
use crate::param::{Param, Params}; use crate::param::{Param, Params};
use crate::peerstate::{Peerstate, PeerstateVerifiedStatus}; use crate::peerstate::{Peerstate, PeerstateVerifiedStatus};
use crate::provider::Socket;
use crate::stock::StockMessage; use crate::stock::StockMessage;
/// An object representing a single contact in memory. /// An object representing a single contact in memory.
@@ -687,29 +686,32 @@ impl Contact {
/// of the contact and if the connection is encrypted the /// of the contact and if the connection is encrypted the
/// fingerprints of the keys involved. /// fingerprints of the keys involved.
pub async fn get_encrinfo(context: &Context, contact_id: u32) -> Result<String> { pub async fn get_encrinfo(context: &Context, contact_id: u32) -> Result<String> {
ensure!(
contact_id > DC_CONTACT_ID_LAST_SPECIAL,
"Can not provide encryption info for special contact"
);
let mut ret = String::new(); let mut ret = String::new();
if let Ok(contact) = Contact::load_from_db(context, contact_id).await { if let Ok(contact) = Contact::load_from_db(context, contact_id).await {
let peerstate = Peerstate::from_addr(context, &contact.addr).await?;
let loginparam = LoginParam::from_database(context, "configured_").await; let loginparam = LoginParam::from_database(context, "configured_").await;
let peerstate = Peerstate::from_addr(context, &contact.addr).await?;
if peerstate.is_some() if let Some(peerstate) = peerstate.filter(|peerstate| {
&& peerstate peerstate
.as_ref() .peek_key(PeerstateVerifiedStatus::Unverified)
.and_then(|p| p.peek_key(PeerstateVerifiedStatus::Unverified))
.is_some() .is_some()
{ }) {
let peerstate = peerstate.as_ref().unwrap(); let stock_message = match peerstate.prefer_encrypt {
let p = context EncryptPreference::Mutual => StockMessage::E2ePreferred,
.stock_str(if peerstate.prefer_encrypt == EncryptPreference::Mutual { EncryptPreference::NoPreference => StockMessage::E2eAvailable,
StockMessage::E2ePreferred EncryptPreference::Reset => StockMessage::EncrNone,
} else { };
StockMessage::E2eAvailable
}) ret += &format!(
.await; "{}\n{}:",
ret += &p; context.stock_str(stock_message).await,
let p = context.stock_str(StockMessage::FingerPrints).await; context.stock_str(StockMessage::FingerPrints).await
ret += &format!(" {}:", p); );
let fingerprint_self = SignedPublicKey::load_self(context) let fingerprint_self = SignedPublicKey::load_self(context)
.await? .await?
@@ -740,10 +742,6 @@ impl Contact {
); );
cat_fingerprint(&mut ret, &loginparam.addr, &fingerprint_self, ""); cat_fingerprint(&mut ret, &loginparam.addr, &fingerprint_self, "");
} }
} else if loginparam.imap.security != Socket::Plain
&& loginparam.smtp.security != Socket::Plain
{
ret += &context.stock_str(StockMessage::EncrTransp).await;
} else { } else {
ret += &context.stock_str(StockMessage::EncrNone).await; ret += &context.stock_str(StockMessage::EncrNone).await;
} }
@@ -1228,6 +1226,7 @@ fn split_address_book(book: &str) -> Vec<(&str, &str)> {
mod tests { mod tests {
use super::*; use super::*;
use crate::chat::send_text_msg;
use crate::test_utils::TestContext; use crate::test_utils::TestContext;
#[test] #[test]
@@ -1614,4 +1613,47 @@ mod tests {
.unwrap(); .unwrap();
assert_eq!(id, Some(DC_CONTACT_ID_SELF)); assert_eq!(id, Some(DC_CONTACT_ID_SELF));
} }
#[async_std::test]
async fn test_contact_get_encrinfo() -> Result<()> {
let alice = TestContext::new_alice().await;
// Return error for special IDs
let encrinfo = Contact::get_encrinfo(&alice, DC_CONTACT_ID_SELF).await;
assert!(encrinfo.is_err());
let encrinfo = Contact::get_encrinfo(&alice, DC_CONTACT_ID_DEVICE).await;
assert!(encrinfo.is_err());
let (contact_bob_id, _modified) =
Contact::add_or_lookup(&alice, "Bob", "bob@example.net", Origin::ManuallyCreated)
.await?;
let encrinfo = Contact::get_encrinfo(&alice, contact_bob_id).await?;
assert_eq!(encrinfo, "No encryption.");
let bob = TestContext::new_bob().await;
let chat_alice = bob
.create_chat_with_contact("Alice", "alice@example.com")
.await;
send_text_msg(&bob, chat_alice.id, "Hello".to_string()).await?;
let msg = bob.pop_sent_msg().await;
alice.recv_msg(&msg).await;
let encrinfo = Contact::get_encrinfo(&alice, contact_bob_id).await?;
assert_eq!(
encrinfo,
"End-to-end encryption preferred.
Fingerprints:
alice@example.com:
2E6F A2CB 23B5 32D7 2863
4B58 64B0 8F61 A9ED 9443
bob@example.net:
CCCB 5AA9 F6E1 141C 9431
65F1 DB18 B18C BCF7 0487"
);
Ok(())
}
} }

View File

@@ -84,9 +84,6 @@ pub enum StockMessage {
#[strum(props(fallback = "End-to-end encryption available."))] #[strum(props(fallback = "End-to-end encryption available."))]
E2eAvailable = 25, E2eAvailable = 25,
#[strum(props(fallback = "Transport-encryption."))]
EncrTransp = 27,
#[strum(props(fallback = "No encryption."))] #[strum(props(fallback = "No encryption."))]
EncrNone = 28, EncrNone = 28,