Compare commits

...

4 Commits

Author SHA1 Message Date
Sebastian Klähn
c284794ac2 double newline 2024-11-10 13:33:40 +01:00
Sebastian Klähn
e494226120 optional \n 2024-11-10 13:25:35 +01:00
Sebastian Klähn
276db00312 jsonrpc(feat): Add API to get json encryption info #6192
Add a new api to jsonrpc that returns json structured data about chat encryption.

close #4642
2024-11-10 12:22:54 +01:00
Sebastian Klähn
5fde02f9fd jsonrpc(feat): Add API to get json encryption info
Add a new api to jsonrpc that returns json structured data about chat encryption.
2024-11-10 11:45:28 +01:00
3 changed files with 89 additions and 36 deletions

View File

@@ -45,7 +45,7 @@ pub mod types;
use num_traits::FromPrimitive;
use types::account::Account;
use types::chat::FullChat;
use types::chat::{EncryptionInfo, FullChat};
use types::contact::{ContactObject, VcardContact};
use types::events::Event;
use types::http::HttpResponse;
@@ -708,6 +708,19 @@ impl CommandApi {
ChatId::new(chat_id).get_encryption_info(&ctx).await
}
/// Get encryption info for a chat.
async fn get_chat_encryption_info_json(
&self,
account_id: u32,
chat_id: u32,
) -> Result<EncryptionInfo> {
let ctx = self.get_context(account_id).await?;
Ok(ChatId::new(chat_id)
.get_encryption_info_json(&ctx)
.await?
.into())
}
/// Get QR code text that will offer a [SecureJoin](https://securejoin.delta.chat/) invitation.
///
/// If `chat_id` is a group chat ID, SecureJoin QR code for the group is returned.

View File

@@ -9,6 +9,7 @@ use deltachat::context::Context;
use num_traits::cast::ToPrimitive;
use serde::{Deserialize, Serialize};
use typescript_type_def::TypeDef;
use yerpc::JsonSchema;
use super::color_int_to_hex_string;
use super::contact::ContactObject;
@@ -239,3 +240,23 @@ impl JSONRPCChatVisibility {
}
}
}
#[derive(Debug, JsonSchema, TypeDef, Serialize, Deserialize)]
pub struct EncryptionInfo {
/// Addresses with End-to-end encryption preferred.
pub mutual: Vec<String>,
/// Addresses with End-to-end encryption available.
pub no_preference: Vec<String>,
/// Addresses with no encryption.
pub reset: Vec<String>,
}
impl From<chat::EncryptionInfo> for EncryptionInfo {
fn from(encryption_info: chat::EncryptionInfo) -> Self {
EncryptionInfo {
mutual: encryption_info.mutual,
no_preference: encryption_info.no_preference,
reset: encryption_info.reset,
}
}
}

View File

@@ -105,6 +105,17 @@ pub enum ProtectionStatus {
ProtectionBroken = 3, // `2` was never used as a value.
}
/// Encryption info for a single chat.
#[derive(Debug)]
pub struct EncryptionInfo {
/// Addresses with End-to-end encryption preferred.
pub mutual: Vec<String>,
/// Addresses with End-to-end encryption available.
pub no_preference: Vec<String>,
/// Addresses with no encryption.
pub reset: Vec<String>,
}
/// The reason why messages cannot be sent to the chat.
///
/// The reason is mainly for logging and displaying in debug REPL, thus not translated.
@@ -1283,9 +1294,39 @@ impl ChatId {
///
/// To get more verbose summary for a contact, including its key fingerprint, use [`Contact::get_encrinfo`].
pub async fn get_encryption_info(self, context: &Context) -> Result<String> {
let mut ret_mutual = String::new();
let mut ret_nopreference = String::new();
let mut ret_reset = String::new();
let encr_info = self.get_encryption_info_json(context).await?;
let mut ret = String::new();
if !encr_info.reset.is_empty() {
ret += &stock_str::encr_none(context).await;
ret.push_str(":\n");
ret += &encr_info.reset.join("\n");
}
if !encr_info.no_preference.is_empty() {
if !ret.is_empty() {
ret.push_str("\n\n");
}
ret += &stock_str::e2e_available(context).await;
ret.push_str(":\n");
ret += &encr_info.no_preference.join("\n");
}
if !encr_info.mutual.is_empty() {
if !ret.is_empty() {
ret.push_str("\n\n");
}
ret += &stock_str::e2e_preferred(context).await;
ret.push_str(":\n");
ret += &encr_info.mutual.join("\n");
}
Ok(ret)
}
/// Returns encryption preferences of all chat contacts.
pub async fn get_encryption_info_json(self, context: &Context) -> Result<EncryptionInfo> {
let mut mutual = vec![];
let mut no_preference = vec![];
let mut reset = vec![];
for contact_id in get_chat_contacts(context, self)
.await?
@@ -1293,46 +1334,24 @@ impl ChatId {
.filter(|&contact_id| !contact_id.is_special())
{
let contact = Contact::get_by_id(context, *contact_id).await?;
let addr = contact.get_addr();
let peerstate = Peerstate::from_addr(context, addr).await?;
let addr = contact.get_addr().to_string();
let peerstate = Peerstate::from_addr(context, &addr).await?;
match peerstate
.filter(|peerstate| peerstate.peek_key(false).is_some())
.map(|peerstate| peerstate.prefer_encrypt)
{
Some(EncryptPreference::Mutual) => ret_mutual += &format!("{addr}\n"),
Some(EncryptPreference::NoPreference) => ret_nopreference += &format!("{addr}\n"),
Some(EncryptPreference::Reset) | None => ret_reset += &format!("{addr}\n"),
Some(EncryptPreference::Mutual) => mutual.push(addr),
Some(EncryptPreference::NoPreference) => no_preference.push(addr),
Some(EncryptPreference::Reset) | None => reset.push(addr),
};
}
let mut ret = String::new();
if !ret_reset.is_empty() {
ret += &stock_str::encr_none(context).await;
ret.push(':');
ret.push('\n');
ret += &ret_reset;
}
if !ret_nopreference.is_empty() {
if !ret.is_empty() {
ret.push('\n');
}
ret += &stock_str::e2e_available(context).await;
ret.push(':');
ret.push('\n');
ret += &ret_nopreference;
}
if !ret_mutual.is_empty() {
if !ret.is_empty() {
ret.push('\n');
}
ret += &stock_str::e2e_preferred(context).await;
ret.push(':');
ret.push('\n');
ret += &ret_mutual;
}
Ok(ret.trim().to_string())
Ok(EncryptionInfo {
mutual,
no_preference,
reset,
})
}
/// Bad evil escape hatch.