replace chat.is_verified() by chat.is_protected()

This commit is contained in:
B. Petersen
2020-10-01 19:29:27 +02:00
parent ab8bf3c2f3
commit b8a55f3aa4
8 changed files with 46 additions and 34 deletions

View File

@@ -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), * 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. * 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. * 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 context The context object.
* @param chat_id If set to a group-chat-id, * @param chat_id If set to a group-chat-id,
* the Verified-Group-Invite protocol is offered in the QR code; * 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. * If set to 0, the Setup-Contact protocol is offered in the QR code.
* See https://countermitm.readthedocs.io/en/latest/new.html * See https://countermitm.readthedocs.io/en/latest/new.html
* for details about both protocols. * 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. * When the protocol has finished, an info-message is added to that chat.
* - If the given QR code starts the Verified-Group-Invite protocol, * - If the given QR code starts the Verified-Group-Invite protocol,
* the function waits until the protocol has finished. * 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. * and can be created only when the contacts have verified each other.
* *
* See https://countermitm.readthedocs.io/en/latest/new.html * 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(). * to dc_check_qr().
* @return Chat-id of the joined chat, the UI may redirect to the this chat. * @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. * 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. * 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_verified() and dc_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. * 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); 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 * Check if a chat is protected.
* and encryption is alwasy enabled. Verified chats are created using * Protected chats contain only verified members and encryption is always enabled.
* dc_create_group_chat() by setting the 'verified' parameter to true. * 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 * @memberof dc_chat_t
* @param chat The chat object. * @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
/** /**

View File

@@ -2389,13 +2389,13 @@ pub unsafe extern "C" fn dc_chat_can_send(chat: *mut dc_chat_t) -> libc::c_int {
} }
#[no_mangle] #[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() { if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_is_verified()"); eprintln!("ignoring careless call to dc_chat_is_protected()");
return 0; return 0;
} }
let ffi_chat = &*chat; let ffi_chat = &*chat;
ffi_chat.chat.is_verified() as libc::c_int ffi_chat.chat.is_protected() as libc::c_int
} }
#[no_mangle] #[no_mangle]

View File

@@ -523,7 +523,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
for i in (0..cnt).rev() { for i in (0..cnt).rev() {
let chat = Chat::load_from_db(&context, chatlist.get_chat_id(i)).await?; let chat = Chat::load_from_db(&context, chatlist.get_chat_id(i)).await?;
println!( println!(
"{}#{}: {} [{} fresh] {}", "{}#{}: {} [{} fresh] {}{}",
chat_prefix(&chat), chat_prefix(&chat),
chat.get_id(), chat.get_id(),
chat.get_name(), chat.get_name(),
@@ -533,6 +533,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
ChatVisibility::Archived => "📦", ChatVisibility::Archived => "📦",
ChatVisibility::Pinned => "📌", ChatVisibility::Pinned => "📌",
}, },
if chat.is_protected() { "🛡️" } else { "" },
); );
let lot = chatlist.get_summary(&context, i, Some(&chat)).await; let lot = chatlist.get_summary(&context, i, Some(&chat)).await;
let statestr = if chat.visibility == ChatVisibility::Archived { 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()) format!("{} member(s)", members.len())
}; };
println!( println!(
"{}#{}: {} [{}]{}{}", "{}#{}: {} [{}]{}{} {}",
chat_prefix(sel_chat), chat_prefix(sel_chat),
sel_chat.get_id(), sel_chat.get_id(),
sel_chat.get_name(), sel_chat.get_name(),
@@ -624,6 +625,11 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
}, },
_ => "".to_string(), _ => "".to_string(),
}, },
if sel_chat.is_protected() {
"🛡️"
} else {
""
},
); );
log_msglist(&context, &msglist).await?; log_msglist(&context, &msglist).await?;
if let Some(draft) = sel_chat.get_id().get_draft(&context).await? { if let Some(draft) = sel_chat.get_id().get_draft(&context).await? {

View File

@@ -85,12 +85,12 @@ class Chat(object):
""" """
return not lib.dc_chat_is_unpromoted(self._dc_chat) 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. """ return True if this chat is a verified group.
:returns: True if chat is verified, False otherwise. :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): def get_name(self):
""" return name of this chat. """ return name of this chat.

View File

@@ -1343,7 +1343,7 @@ class TestOnlineAccount:
ac1, ac2 = acfactory.get_two_online_accounts() ac1, ac2 = acfactory.get_two_online_accounts()
lp.sec("ac1: create verified-group QR, ac2 scans and joins") lp.sec("ac1: create verified-group QR, ac2 scans and joins")
chat1 = ac1.create_group_chat("hello", verified=True) chat1 = ac1.create_group_chat("hello", verified=True)
assert chat1.is_verified() assert chat1.is_protected()
qr = chat1.get_join_qr() qr = chat1.get_join_qr()
lp.sec("ac2: start QR-code based join-group protocol") lp.sec("ac2: start QR-code based join-group protocol")
chat2 = ac2.qr_join_chat(qr) chat2 = ac2.qr_join_chat(qr)
@@ -1362,7 +1362,7 @@ class TestOnlineAccount:
lp.sec("ac2: read message and check it's verified chat") lp.sec("ac2: read message and check it's verified chat")
msg = ac2._evtracker.wait_next_incoming_message() msg = ac2._evtracker.wait_next_incoming_message()
assert msg.text == "hello" assert msg.text == "hello"
assert msg.chat.is_verified() assert msg.chat.is_protected()
assert msg.is_encrypted() assert msg.is_encrypted()
lp.sec("ac2: send message and let ac1 read it") lp.sec("ac2: send message and let ac1 read it")

View File

@@ -566,6 +566,7 @@ pub struct Chat {
pub param: Params, pub param: Params,
is_sending_locations: bool, is_sending_locations: bool,
pub mute_duration: MuteDuration, pub mute_duration: MuteDuration,
protected: ProtectionStatus,
} }
impl Chat { impl Chat {
@@ -575,7 +576,7 @@ impl Chat {
.sql .sql
.query_row( .query_row(
"SELECT c.type, c.name, c.grpid, c.param, c.archived, "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 FROM chats c
WHERE c.id=?;", WHERE c.id=?;",
paramsv![chat_id], paramsv![chat_id],
@@ -590,6 +591,7 @@ impl Chat {
blocked: row.get::<_, Option<_>>(5)?.unwrap_or_default(), blocked: row.get::<_, Option<_>>(5)?.unwrap_or_default(),
is_sending_locations: row.get(6)?, is_sending_locations: row.get(6)?,
mute_duration: row.get(7)?, mute_duration: row.get(7)?,
protected: row.get(8)?,
}; };
Ok(c) Ok(c)
}, },
@@ -755,9 +757,9 @@ impl Chat {
!self.is_unpromoted() !self.is_unpromoted()
} }
/// Returns true if chat is a verified group chat. /// Returns true if chat protection is enabled.
pub fn is_verified(&self) -> bool { pub fn is_protected(&self) -> bool {
self.typ == Chattype::VerifiedGroup self.protected == ProtectionStatus::Protected
} }
/// Returns true if location streaming is enabled in the chat. /// Returns true if location streaming is enabled in the chat.
@@ -2062,7 +2064,7 @@ pub(crate) async fn add_contact_to_chat_ex(
{ {
error!( error!(
context, context,
"Only bidirectional verified contacts can be added to verified groups." "Only bidirectional verified contacts can be added to protected chats."
); );
return Ok(false); 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( pub(crate) async fn get_chat_id_by_grpid(
context: &Context, context: &Context,
grpid: impl AsRef<str>, grpid: impl AsRef<str>,
@@ -2634,14 +2636,16 @@ pub(crate) async fn get_chat_id_by_grpid(
context context
.sql .sql
.query_row( .query_row(
"SELECT id, blocked, type FROM chats WHERE grpid=?;", "SELECT id, blocked, protected FROM chats WHERE grpid=?;",
paramsv![grpid.as_ref()], paramsv![grpid.as_ref()],
|row| { |row| {
let chat_id = row.get::<_, ChatId>(0)?; let chat_id = row.get::<_, ChatId>(0)?;
let b = row.get::<_, Option<Blocked>>(1)?.unwrap_or_default(); let b = row.get::<_, Option<Blocked>>(1)?.unwrap_or_default();
let v = row.get::<_, Option<Chattype>>(2)?.unwrap_or_default(); let p = row
Ok((chat_id, v == Chattype::VerifiedGroup, b)) .get::<_, Option<ProtectionStatus>>(2)?
.unwrap_or_default();
Ok((chat_id, p == ProtectionStatus::Protected, b))
}, },
) )
.await .await

View File

@@ -1731,7 +1731,7 @@ async fn check_verified_properties(
} }
if !is_verified { if !is_verified {
bail!( bail!(
"{} is not a member of this verified group", "{} is not a member of this protected chat",
to_addr.to_string() to_addr.to_string()
); );
} }

View File

@@ -348,7 +348,7 @@ async fn securejoin(context: &Context, qr: &str) -> Result<ChatId, JoinError> {
let bob = context.bob.read().await; let bob = context.bob.read().await;
let grpid = bob.qr_scan.as_ref().unwrap().text2.as_ref().unwrap(); let grpid = bob.qr_scan.as_ref().unwrap().text2.as_ref().unwrap();
match chat::get_chat_id_by_grpid(context, grpid).await { 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) => { Err(err) => {
if start.elapsed() > Duration::from_secs(7) { if start.elapsed() > Duration::from_secs(7) {
return Err(JoinError::MissingChat(err)); return Err(JoinError::MissingChat(err));
@@ -791,19 +791,19 @@ pub(crate) async fn handle_securejoin_handshake(
let vg_expect_encrypted = if join_vg { let vg_expect_encrypted = if join_vg {
let group_id = get_qr_attr!(context, text2).to_string(); 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 // false since the group is created by receive_imf by
// the very handshake message we're handling now. But // the very handshake message we're handling now. But
// only after we have returned. It does not impact // only after we have returned. It does not impact
// the security invariants of secure-join however. // 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 .await
.unwrap_or((ChatId::new(0), false, Blocked::Not)); .unwrap_or((ChatId::new(0), false, Blocked::Not));
// when joining a non-verified group // when joining a non-verified group
// the vg-member-added message may be unencrypted // the vg-member-added message may be unencrypted
// when not all group members have keys or prefer encryption. // when not all group members have keys or prefer encryption.
// So only expect encryption if this is a verified group // So only expect encryption if this is a verified group
is_verified_group is_protected_group
} else { } else {
// setup contact is always encrypted // setup contact is always encrypted
true true
@@ -1428,6 +1428,6 @@ mod tests {
let bob_chatid = joiner.await; let bob_chatid = joiner.await;
let bob_chat = Chat::load_from_db(&bob.ctx, bob_chatid).await.unwrap(); let bob_chat = Chat::load_from_db(&bob.ctx, bob_chatid).await.unwrap();
assert!(bob_chat.is_verified()); assert!(bob_chat.is_protected());
} }
} }