mirror of
https://github.com/chatmail/core.git
synced 2026-05-24 17:26:30 +03:00
api: add dc_contact_is_profile_verified()
This commit is contained in:
@@ -3743,13 +3743,9 @@ int dc_chat_can_send (const dc_chat_t* chat);
|
|||||||
* if `verified_one_on_one_chats` setting is enabled.
|
* if `verified_one_on_one_chats` setting is enabled.
|
||||||
*
|
*
|
||||||
* UI should display a green checkmark
|
* UI should display a green checkmark
|
||||||
* in the chat title,
|
* in the chat title and
|
||||||
* in the chat profile title and
|
|
||||||
* in the chatlist item
|
* in the chatlist item
|
||||||
* if chat protection is enabled.
|
* if chat protection is enabled.
|
||||||
* UI should also display a green checkmark
|
|
||||||
* in the contact profile
|
|
||||||
* if 1:1 chat with this contact exists and is protected.
|
|
||||||
*
|
*
|
||||||
* @memberof dc_chat_t
|
* @memberof dc_chat_t
|
||||||
* @param chat The chat object.
|
* @param chat The chat object.
|
||||||
@@ -5061,9 +5057,7 @@ int dc_contact_is_blocked (const dc_contact_t* contact);
|
|||||||
*
|
*
|
||||||
* Do not use this function when displaying the contact profile view.
|
* Do not use this function when displaying the contact profile view.
|
||||||
* Display green checkmark in the title of the contact profile
|
* Display green checkmark in the title of the contact profile
|
||||||
* if 1:1 chat with the contact exists and is protected.
|
* if dc_contact_profile_is_verified() returns true.
|
||||||
* Use dc_contact_get_verified_id to display the verifier contact
|
|
||||||
* in the info section of the contact profile.
|
|
||||||
*
|
*
|
||||||
* @memberof dc_contact_t
|
* @memberof dc_contact_t
|
||||||
* @param contact The contact object.
|
* @param contact The contact object.
|
||||||
@@ -5073,6 +5067,23 @@ int dc_contact_is_blocked (const dc_contact_t* contact);
|
|||||||
int dc_contact_is_verified (dc_contact_t* contact);
|
int dc_contact_is_verified (dc_contact_t* contact);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the contact profile title
|
||||||
|
* should contain a green checkmark.
|
||||||
|
* This indicates whether 1:1 chat with
|
||||||
|
* this contact has a green checkmark
|
||||||
|
* or will have if such chat is created.
|
||||||
|
*
|
||||||
|
* Use dc_contact_get_verified_id to display the verifier contact
|
||||||
|
* in the info section of the contact profile.
|
||||||
|
*
|
||||||
|
* @memberof dc_contact_t
|
||||||
|
* @param contact The contact object.
|
||||||
|
* @return 1=contact profile has a green checkmark in the title,
|
||||||
|
* 0=contact profile has no green checkmark in the title.
|
||||||
|
*/
|
||||||
|
int dc_contact_profile_is_verified (dc_contact_t* contact);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the contact ID that verified a contact.
|
* Return the contact ID that verified a contact.
|
||||||
|
|||||||
@@ -4119,6 +4119,21 @@ pub unsafe extern "C" fn dc_contact_is_verified(contact: *mut dc_contact_t) -> l
|
|||||||
.unwrap_or_default() as libc::c_int
|
.unwrap_or_default() as libc::c_int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn dc_contact_profile_is_verified(contact: *mut dc_contact_t) -> libc::c_int {
|
||||||
|
if contact.is_null() {
|
||||||
|
eprintln!("ignoring careless call to dc_contact_profile_is_verified()");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let ffi_contact = &*contact;
|
||||||
|
let ctx = &*ffi_contact.context;
|
||||||
|
|
||||||
|
block_on(ffi_contact.contact.is_profile_verified(ctx))
|
||||||
|
.context("is_profile_verified failed")
|
||||||
|
.log_err(ctx)
|
||||||
|
.unwrap_or_default() as libc::c_int
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn dc_contact_get_verifier_id(contact: *mut dc_contact_t) -> u32 {
|
pub unsafe extern "C" fn dc_contact_get_verifier_id(contact: *mut dc_contact_t) -> u32 {
|
||||||
if contact.is_null() {
|
if contact.is_null() {
|
||||||
|
|||||||
@@ -24,11 +24,16 @@ pub struct ContactObject {
|
|||||||
///
|
///
|
||||||
/// If this is true
|
/// If this is true
|
||||||
/// UI should display green checkmark after the contact name
|
/// UI should display green checkmark after the contact name
|
||||||
/// in the title of the contact profile,
|
|
||||||
/// in contact list items and
|
/// in contact list items and
|
||||||
/// in chat member list items.
|
/// in chat member list items.
|
||||||
is_verified: bool,
|
is_verified: bool,
|
||||||
|
|
||||||
|
/// True if the contact profile title should have a green checkmark.
|
||||||
|
///
|
||||||
|
/// This indicates whether 1:1 chat has a green checkmark
|
||||||
|
/// or will have a green checkmark if created.
|
||||||
|
is_profile_verified: bool,
|
||||||
|
|
||||||
/// The ID of the contact that verified this contact.
|
/// The ID of the contact that verified this contact.
|
||||||
///
|
///
|
||||||
/// If this is present,
|
/// If this is present,
|
||||||
@@ -52,6 +57,7 @@ impl ContactObject {
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
let is_verified = contact.is_verified(context).await? == VerifiedStatus::BidirectVerified;
|
let is_verified = contact.is_verified(context).await? == VerifiedStatus::BidirectVerified;
|
||||||
|
let is_profile_verified = contact.is_profile_verified(context).await?;
|
||||||
|
|
||||||
let verifier_id = contact
|
let verifier_id = contact
|
||||||
.get_verifier_id(context)
|
.get_verifier_id(context)
|
||||||
@@ -70,6 +76,7 @@ impl ContactObject {
|
|||||||
name_and_addr: contact.get_name_n_addr(),
|
name_and_addr: contact.get_name_n_addr(),
|
||||||
is_blocked: contact.is_blocked(),
|
is_blocked: contact.is_blocked(),
|
||||||
is_verified,
|
is_verified,
|
||||||
|
is_profile_verified,
|
||||||
verifier_id,
|
verifier_id,
|
||||||
last_seen: contact.last_seen(),
|
last_seen: contact.last_seen(),
|
||||||
was_seen_recently: contact.was_seen_recently(),
|
was_seen_recently: contact.was_seen_recently(),
|
||||||
|
|||||||
@@ -391,6 +391,18 @@ def test_qr_setup_contact(acfactory) -> None:
|
|||||||
if event["kind"] == "SecurejoinInviterProgress" and event["progress"] == 1000:
|
if event["kind"] == "SecurejoinInviterProgress" and event["progress"] == 1000:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Test that scanning Alice's QR code verifies Alice's profile.
|
||||||
|
bob_contact_alice = bob.get_contact_by_addr(alice.get_config("addr"))
|
||||||
|
bob_contact_alice_snapshot = bob_contact_alice.get_snapshot()
|
||||||
|
assert bob_contact_alice_snapshot.is_verified
|
||||||
|
assert bob_contact_alice_snapshot.is_profile_verified
|
||||||
|
|
||||||
|
# Test that Alice symmetrically verified Bob's profile.
|
||||||
|
alice_contact_bob = alice.get_contact_by_addr(bob.get_config("addr"))
|
||||||
|
alice_contact_bob_snapshot = alice_contact_bob.get_snapshot()
|
||||||
|
assert alice_contact_bob_snapshot.is_verified
|
||||||
|
assert alice_contact_bob_snapshot.is_profile_verified
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail()
|
@pytest.mark.xfail()
|
||||||
def test_verified_group_recovery(acfactory, rpc) -> None:
|
def test_verified_group_recovery(acfactory, rpc) -> None:
|
||||||
|
|||||||
15
src/chat.rs
15
src/chat.rs
@@ -208,9 +208,10 @@ impl ChatId {
|
|||||||
self == DC_CHAT_ID_ALLDONE_HINT
|
self == DC_CHAT_ID_ALLDONE_HINT
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [`ChatId`] for the 1:1 chat with `contact_id` if it exists.
|
/// Returns the [`ChatId`] for the 1:1 chat with `contact_id`
|
||||||
|
/// if it exists and is not blocked.
|
||||||
///
|
///
|
||||||
/// If it does not exist, `None` is returned.
|
/// If the chat does not exist or is blocked, `None` is returned.
|
||||||
pub async fn lookup_by_contact(
|
pub async fn lookup_by_contact(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
contact_id: ContactId,
|
contact_id: ContactId,
|
||||||
@@ -1251,6 +1252,16 @@ impl ChatId {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the chat is protected.
|
||||||
|
pub async fn is_protected(self, context: &Context) -> Result<ProtectionStatus> {
|
||||||
|
let protection_status = context
|
||||||
|
.sql
|
||||||
|
.query_get_value("SELECT protected FROM chats WHERE id=?", (self,))
|
||||||
|
.await?
|
||||||
|
.unwrap_or_default();
|
||||||
|
Ok(protection_status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for ChatId {
|
impl std::fmt::Display for ChatId {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ use tokio::task;
|
|||||||
use tokio::time::{timeout, Duration};
|
use tokio::time::{timeout, Duration};
|
||||||
|
|
||||||
use crate::aheader::EncryptPreference;
|
use crate::aheader::EncryptPreference;
|
||||||
use crate::chat::ChatId;
|
use crate::chat::{ChatId, ProtectionStatus};
|
||||||
use crate::color::str_to_color;
|
use crate::color::str_to_color;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::constants::{Blocked, Chattype, DC_GCL_ADD_SELF, DC_GCL_VERIFIED_ONLY};
|
use crate::constants::{Blocked, Chattype, DC_GCL_ADD_SELF, DC_GCL_VERIFIED_ONLY};
|
||||||
@@ -1263,7 +1263,7 @@ impl Contact {
|
|||||||
///
|
///
|
||||||
/// Do not use this function when displaying the contact profile view.
|
/// Do not use this function when displaying the contact profile view.
|
||||||
/// Display green checkmark in the title of the contact profile
|
/// Display green checkmark in the title of the contact profile
|
||||||
/// if 1:1 chat with the contact exists and is protected.
|
/// if [Self::is_profile_verified] returns true.
|
||||||
/// Use [Self::get_verifier_id] to display the verifier contact
|
/// Use [Self::get_verifier_id] to display the verifier contact
|
||||||
/// in the info section of the contact profile.
|
/// in the info section of the contact profile.
|
||||||
pub async fn is_verified(&self, context: &Context) -> Result<VerifiedStatus> {
|
pub async fn is_verified(&self, context: &Context) -> Result<VerifiedStatus> {
|
||||||
@@ -1317,6 +1317,22 @@ impl Contact {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns if the contact profile title should display a green checkmark.
|
||||||
|
///
|
||||||
|
/// This generally should be consistent with the 1:1 chat with the contact
|
||||||
|
/// so 1:1 chat with the contact and the contact profile
|
||||||
|
/// either both display the green checkmark or both don't display a green checkmark.
|
||||||
|
pub async fn is_profile_verified(&self, context: &Context) -> Result<bool> {
|
||||||
|
let contact_id = self.id;
|
||||||
|
|
||||||
|
if let Some(chat_id) = ChatId::lookup_by_contact(context, contact_id).await? {
|
||||||
|
Ok(chat_id.is_protected(context).await? == ProtectionStatus::Protected)
|
||||||
|
} else {
|
||||||
|
// 1:1 chat does not exist.
|
||||||
|
Ok(self.is_verified(context).await? == VerifiedStatus::BidirectVerified)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the number of real (i.e. non-special) contacts in the database.
|
/// Returns the number of real (i.e. non-special) contacts in the database.
|
||||||
pub async fn get_real_cnt(context: &Context) -> Result<usize> {
|
pub async fn get_real_cnt(context: &Context) -> Result<usize> {
|
||||||
if !context.sql.is_open().await {
|
if !context.sql.is_open().await {
|
||||||
|
|||||||
Reference in New Issue
Block a user