From b8a55f3aa4b58a75a7e79758ea877fb404096a46 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 1 Oct 2020 19:29:27 +0200 Subject: [PATCH] replace chat.is_verified() by chat.is_protected() --- deltachat-ffi/deltachat.h | 22 ++++++++++++---------- deltachat-ffi/src/lib.rs | 6 +++--- examples/repl/cmdline.rs | 10 ++++++++-- python/src/deltachat/chat.py | 4 ++-- python/tests/test_account.py | 4 ++-- src/chat.rs | 22 +++++++++++++--------- src/dc_receive_imf.rs | 2 +- src/securejoin.rs | 10 +++++----- 8 files changed, 46 insertions(+), 34 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 434c7bc2d..4a14d7d3a 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -1329,7 +1329,7 @@ int dc_is_contact_in_chat (dc_context_t* context, uint32_t ch * If the group is already _promoted_ (any message was sent to the group), * all group members are informed by a special status message that is sent automatically by this function. * - * If the group is a verified group, only verified contacts can be added to the group. + * If the group has group protection enabled, only verified contacts can be added to the group. * * Sends out #DC_EVENT_CHAT_MODIFIED and #DC_EVENT_MSGS_CHANGED if a status message was sent. * @@ -1973,7 +1973,7 @@ dc_lot_t* dc_check_qr (dc_context_t* context, const char* * @param context The context object. * @param chat_id If set to a group-chat-id, * the Verified-Group-Invite protocol is offered in the QR code; - * works for verified groups as well as for normal groups. + * works for protected groups as well as for normal groups. * If set to 0, the Setup-Contact protocol is offered in the QR code. * See https://countermitm.readthedocs.io/en/latest/new.html * for details about both protocols. @@ -2003,7 +2003,7 @@ char* dc_get_securejoin_qr (dc_context_t* context, uint32_t ch * When the protocol has finished, an info-message is added to that chat. * - If the given QR code starts the Verified-Group-Invite protocol, * the function waits until the protocol has finished. - * This is because the verified group is not opportunistic + * This is because the protected group is not opportunistic * and can be created only when the contacts have verified each other. * * See https://countermitm.readthedocs.io/en/latest/new.html @@ -2015,8 +2015,8 @@ char* dc_get_securejoin_qr (dc_context_t* context, uint32_t ch * to dc_check_qr(). * @return Chat-id of the joined chat, the UI may redirect to the this chat. * If the out-of-band verification failed or was aborted, 0 is returned. - * A returned chat-id does not guarantee that the chat or the belonging contact is verified. - * If needed, this be checked with dc_chat_is_verified() and dc_contact_is_verified(), + * A returned chat-id does not guarantee that the chat is protected or the belonging contact is verified. + * If needed, this be checked with dc_chat_is_protected() and dc_contact_is_verified(), * however, in practise, the UI will just listen to #DC_EVENT_CONTACTS_CHANGED unconditionally. */ uint32_t dc_join_securejoin (dc_context_t* context, const char* qr); @@ -2942,15 +2942,17 @@ int dc_chat_can_send (const dc_chat_t* chat); /** - * Check if a chat is verified. Verified chats contain only verified members - * and encryption is alwasy enabled. Verified chats are created using - * dc_create_group_chat() by setting the 'verified' parameter to true. + * Check if a chat is protected. + * Protected chats contain only verified members and encryption is always enabled. + * Protected chats are created using dc_create_group_chat() by setting the 'protect' parameter to 1. + * The status can be changed using dc_set_chat_protection(). * * @memberof dc_chat_t * @param chat The chat object. - * @return 1=chat verified, 0=chat is not verified + * @return 1=chat protected, 0=chat is not protected */ -int dc_chat_is_verified (const dc_chat_t* chat); +int dc_chat_is_protected (const dc_chat_t* chat); +#define dc_chat_is_verified dc_chat_is_protected // allow using old function name for a while /** diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index bf83536f8..394b1bc81 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -2389,13 +2389,13 @@ pub unsafe extern "C" fn dc_chat_can_send(chat: *mut dc_chat_t) -> libc::c_int { } #[no_mangle] -pub unsafe extern "C" fn dc_chat_is_verified(chat: *mut dc_chat_t) -> libc::c_int { +pub unsafe extern "C" fn dc_chat_is_protected(chat: *mut dc_chat_t) -> libc::c_int { if chat.is_null() { - eprintln!("ignoring careless call to dc_chat_is_verified()"); + eprintln!("ignoring careless call to dc_chat_is_protected()"); return 0; } let ffi_chat = &*chat; - ffi_chat.chat.is_verified() as libc::c_int + ffi_chat.chat.is_protected() as libc::c_int } #[no_mangle] diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index a3e49db36..9682a7c55 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -523,7 +523,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu for i in (0..cnt).rev() { let chat = Chat::load_from_db(&context, chatlist.get_chat_id(i)).await?; println!( - "{}#{}: {} [{} fresh] {}", + "{}#{}: {} [{} fresh] {}{}", chat_prefix(&chat), chat.get_id(), chat.get_name(), @@ -533,6 +533,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu ChatVisibility::Archived => "📦", ChatVisibility::Pinned => "📌", }, + if chat.is_protected() { "🛡️" } else { "" }, ); let lot = chatlist.get_summary(&context, i, Some(&chat)).await; let statestr = if chat.visibility == ChatVisibility::Archived { @@ -607,7 +608,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu format!("{} member(s)", members.len()) }; println!( - "{}#{}: {} [{}]{}{}", + "{}#{}: {} [{}]{}{} {}", chat_prefix(sel_chat), sel_chat.get_id(), sel_chat.get_name(), @@ -624,6 +625,11 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu }, _ => "".to_string(), }, + if sel_chat.is_protected() { + "🛡️" + } else { + "" + }, ); log_msglist(&context, &msglist).await?; if let Some(draft) = sel_chat.get_id().get_draft(&context).await? { diff --git a/python/src/deltachat/chat.py b/python/src/deltachat/chat.py index 60860d5a3..30cce4c72 100644 --- a/python/src/deltachat/chat.py +++ b/python/src/deltachat/chat.py @@ -85,12 +85,12 @@ class Chat(object): """ return not lib.dc_chat_is_unpromoted(self._dc_chat) - def is_verified(self): + def is_protected(self): """ return True if this chat is a verified group. :returns: True if chat is verified, False otherwise. """ - return lib.dc_chat_is_verified(self._dc_chat) + return lib.dc_chat_is_protected(self._dc_chat) def get_name(self): """ return name of this chat. diff --git a/python/tests/test_account.py b/python/tests/test_account.py index 543317b1e..e65f27ced 100644 --- a/python/tests/test_account.py +++ b/python/tests/test_account.py @@ -1343,7 +1343,7 @@ class TestOnlineAccount: ac1, ac2 = acfactory.get_two_online_accounts() lp.sec("ac1: create verified-group QR, ac2 scans and joins") chat1 = ac1.create_group_chat("hello", verified=True) - assert chat1.is_verified() + assert chat1.is_protected() qr = chat1.get_join_qr() lp.sec("ac2: start QR-code based join-group protocol") chat2 = ac2.qr_join_chat(qr) @@ -1362,7 +1362,7 @@ class TestOnlineAccount: lp.sec("ac2: read message and check it's verified chat") msg = ac2._evtracker.wait_next_incoming_message() assert msg.text == "hello" - assert msg.chat.is_verified() + assert msg.chat.is_protected() assert msg.is_encrypted() lp.sec("ac2: send message and let ac1 read it") diff --git a/src/chat.rs b/src/chat.rs index 731ed9220..e4b199b8e 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -566,6 +566,7 @@ pub struct Chat { pub param: Params, is_sending_locations: bool, pub mute_duration: MuteDuration, + protected: ProtectionStatus, } impl Chat { @@ -575,7 +576,7 @@ impl Chat { .sql .query_row( "SELECT c.type, c.name, c.grpid, c.param, c.archived, - c.blocked, c.locations_send_until, c.muted_until + c.blocked, c.locations_send_until, c.muted_until, c.protected FROM chats c WHERE c.id=?;", paramsv![chat_id], @@ -590,6 +591,7 @@ impl Chat { blocked: row.get::<_, Option<_>>(5)?.unwrap_or_default(), is_sending_locations: row.get(6)?, mute_duration: row.get(7)?, + protected: row.get(8)?, }; Ok(c) }, @@ -755,9 +757,9 @@ impl Chat { !self.is_unpromoted() } - /// Returns true if chat is a verified group chat. - pub fn is_verified(&self) -> bool { - self.typ == Chattype::VerifiedGroup + /// Returns true if chat protection is enabled. + pub fn is_protected(&self) -> bool { + self.protected == ProtectionStatus::Protected } /// Returns true if location streaming is enabled in the chat. @@ -2062,7 +2064,7 @@ pub(crate) async fn add_contact_to_chat_ex( { error!( context, - "Only bidirectional verified contacts can be added to verified groups." + "Only bidirectional verified contacts can be added to protected chats." ); return Ok(false); } @@ -2626,7 +2628,7 @@ pub(crate) async fn get_chat_cnt(context: &Context) -> usize { } } -/// Returns a tuple of `(chatid, is_verified, blocked)`. +/// Returns a tuple of `(chatid, is_protected, blocked)`. pub(crate) async fn get_chat_id_by_grpid( context: &Context, grpid: impl AsRef, @@ -2634,14 +2636,16 @@ pub(crate) async fn get_chat_id_by_grpid( context .sql .query_row( - "SELECT id, blocked, type FROM chats WHERE grpid=?;", + "SELECT id, blocked, protected FROM chats WHERE grpid=?;", paramsv![grpid.as_ref()], |row| { let chat_id = row.get::<_, ChatId>(0)?; let b = row.get::<_, Option>(1)?.unwrap_or_default(); - let v = row.get::<_, Option>(2)?.unwrap_or_default(); - Ok((chat_id, v == Chattype::VerifiedGroup, b)) + let p = row + .get::<_, Option>(2)? + .unwrap_or_default(); + Ok((chat_id, p == ProtectionStatus::Protected, b)) }, ) .await diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 29a4caf4d..9abc9de6c 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -1731,7 +1731,7 @@ async fn check_verified_properties( } if !is_verified { bail!( - "{} is not a member of this verified group", + "{} is not a member of this protected chat", to_addr.to_string() ); } diff --git a/src/securejoin.rs b/src/securejoin.rs index a7299f827..02abc14c5 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -348,7 +348,7 @@ async fn securejoin(context: &Context, qr: &str) -> Result { let bob = context.bob.read().await; let grpid = bob.qr_scan.as_ref().unwrap().text2.as_ref().unwrap(); match chat::get_chat_id_by_grpid(context, grpid).await { - Ok((chatid, _is_verified, _blocked)) => break chatid, + Ok((chatid, _is_protected, _blocked)) => break chatid, Err(err) => { if start.elapsed() > Duration::from_secs(7) { return Err(JoinError::MissingChat(err)); @@ -791,19 +791,19 @@ pub(crate) async fn handle_securejoin_handshake( let vg_expect_encrypted = if join_vg { let group_id = get_qr_attr!(context, text2).to_string(); - // This is buggy, is_verified_group will always be + // This is buggy, is_protected_group will always be // false since the group is created by receive_imf by // the very handshake message we're handling now. But // only after we have returned. It does not impact // the security invariants of secure-join however. - let (_, is_verified_group, _) = chat::get_chat_id_by_grpid(context, &group_id) + let (_, is_protected_group, _) = chat::get_chat_id_by_grpid(context, &group_id) .await .unwrap_or((ChatId::new(0), false, Blocked::Not)); // when joining a non-verified group // the vg-member-added message may be unencrypted // when not all group members have keys or prefer encryption. // So only expect encryption if this is a verified group - is_verified_group + is_protected_group } else { // setup contact is always encrypted true @@ -1428,6 +1428,6 @@ mod tests { let bob_chatid = joiner.await; let bob_chat = Chat::load_from_db(&bob.ctx, bob_chatid).await.unwrap(); - assert!(bob_chat.is_verified()); + assert!(bob_chat.is_protected()); } }