mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
refactor(peerstate): safe implementation of peerstate
This commit is contained in:
committed by
GitHub
parent
d926b3536d
commit
94aa314f30
@@ -3,7 +3,6 @@ use std::sync::{Arc, RwLock};
|
||||
|
||||
use deltachat::constants::*;
|
||||
use deltachat::dc_aheader::*;
|
||||
use deltachat::dc_apeerstate::*;
|
||||
use deltachat::dc_array::*;
|
||||
use deltachat::dc_chat::*;
|
||||
use deltachat::dc_chatlist::*;
|
||||
@@ -44,6 +43,7 @@ use deltachat::dc_strbuilder::*;
|
||||
use deltachat::dc_strencode::*;
|
||||
use deltachat::dc_token::*;
|
||||
use deltachat::dc_tools::*;
|
||||
use deltachat::peerstate::*;
|
||||
use deltachat::types::*;
|
||||
use deltachat::x::*;
|
||||
use num_traits::FromPrimitive;
|
||||
@@ -407,7 +407,6 @@ unsafe fn log_msglist(context: &dc_context_t, msglist: *mut dc_array_t) {
|
||||
}
|
||||
unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) {
|
||||
let mut contact: *mut dc_contact_t;
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
if !dc_array_search_id(contacts, 1i32 as uint32_t, 0 as *mut size_t) {
|
||||
dc_array_add_id(contacts, 1i32 as uint32_t);
|
||||
}
|
||||
@@ -444,29 +443,14 @@ unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) {
|
||||
b"addr unset\x00" as *const u8 as *const libc::c_char
|
||||
},
|
||||
);
|
||||
let peerstate_ok: libc::c_int = dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
addr,
|
||||
);
|
||||
if 0 != peerstate_ok && contact_id != 1i32 as libc::c_uint {
|
||||
let pe: *mut libc::c_char;
|
||||
match peerstate.prefer_encrypt {
|
||||
1 => pe = dc_strdup(b"mutual\x00" as *const u8 as *const libc::c_char),
|
||||
0 => pe = dc_strdup(b"no-preference\x00" as *const u8 as *const libc::c_char),
|
||||
20 => pe = dc_strdup(b"reset\x00" as *const u8 as *const libc::c_char),
|
||||
_ => {
|
||||
pe = dc_mprintf(
|
||||
b"unknown-value (%i)\x00" as *const u8 as *const libc::c_char,
|
||||
peerstate.prefer_encrypt,
|
||||
)
|
||||
}
|
||||
}
|
||||
let peerstate =
|
||||
Peerstate::from_addr(context, &context.sql.clone().read().unwrap(), to_str(addr));
|
||||
if peerstate.is_some() && contact_id != 1i32 as libc::c_uint {
|
||||
let pe = to_cstring(format!("{}", peerstate.as_ref().unwrap().prefer_encrypt));
|
||||
line2 = dc_mprintf(
|
||||
b", prefer-encrypt=%s\x00" as *const u8 as *const libc::c_char,
|
||||
pe,
|
||||
pe.as_ptr(),
|
||||
);
|
||||
free(pe as *mut libc::c_void);
|
||||
}
|
||||
dc_contact_unref(contact);
|
||||
free(name as *mut libc::c_void);
|
||||
@@ -488,8 +472,8 @@ unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) {
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
}
|
||||
|
||||
static mut s_is_auth: libc::c_int = 0i32;
|
||||
|
||||
pub unsafe fn dc_cmdline_skip_auth() {
|
||||
|
||||
@@ -22,7 +22,6 @@ use std::sync::{Arc, RwLock};
|
||||
|
||||
use deltachat::constants::*;
|
||||
use deltachat::dc_aheader::*;
|
||||
use deltachat::dc_apeerstate::*;
|
||||
use deltachat::dc_array::*;
|
||||
use deltachat::dc_chat::*;
|
||||
use deltachat::dc_chatlist::*;
|
||||
@@ -63,6 +62,7 @@ use deltachat::dc_strbuilder::*;
|
||||
use deltachat::dc_strencode::*;
|
||||
use deltachat::dc_token::*;
|
||||
use deltachat::dc_tools::*;
|
||||
use deltachat::peerstate::*;
|
||||
use deltachat::types::*;
|
||||
use deltachat::x::*;
|
||||
mod cmdline;
|
||||
|
||||
@@ -1,542 +0,0 @@
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::dc_aheader::*;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
use crate::dc_hash::*;
|
||||
use crate::dc_key::*;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
/* prefer-encrypt states */
|
||||
/**
|
||||
* @class dc_apeerstate_t
|
||||
* Library-internal.
|
||||
*/
|
||||
pub struct dc_apeerstate_t<'a> {
|
||||
pub context: &'a dc_context_t,
|
||||
pub addr: *mut libc::c_char,
|
||||
pub last_seen: time_t,
|
||||
pub last_seen_autocrypt: time_t,
|
||||
pub prefer_encrypt: libc::c_int,
|
||||
pub public_key: Option<Key>,
|
||||
pub public_key_fingerprint: *mut libc::c_char,
|
||||
pub gossip_key: Option<Key>,
|
||||
pub gossip_timestamp: time_t,
|
||||
pub gossip_key_fingerprint: *mut libc::c_char,
|
||||
// TODO: this should be a reference to either the public_key or verified_key
|
||||
pub verified_key: Option<Key>,
|
||||
pub verified_key_fingerprint: *mut libc::c_char,
|
||||
pub to_save: libc::c_int,
|
||||
pub degrade_event: libc::c_int,
|
||||
}
|
||||
|
||||
/* the returned pointer is ref'd and must be unref'd after usage */
|
||||
pub fn dc_apeerstate_new<'a>(context: &'a dc_context_t) -> dc_apeerstate_t<'a> {
|
||||
dc_apeerstate_t {
|
||||
context,
|
||||
addr: std::ptr::null_mut(),
|
||||
last_seen: 0,
|
||||
last_seen_autocrypt: 0,
|
||||
prefer_encrypt: 0,
|
||||
public_key: None,
|
||||
public_key_fingerprint: std::ptr::null_mut(),
|
||||
gossip_key: None,
|
||||
gossip_key_fingerprint: std::ptr::null_mut(),
|
||||
gossip_timestamp: 0,
|
||||
verified_key: None,
|
||||
verified_key_fingerprint: std::ptr::null_mut(),
|
||||
to_save: 0,
|
||||
degrade_event: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_unref(peerstate: &mut dc_apeerstate_t) {
|
||||
dc_apeerstate_empty(peerstate);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* dc_apeerstate_t represents the state of an Autocrypt peer - Load/save
|
||||
******************************************************************************/
|
||||
unsafe fn dc_apeerstate_empty(peerstate: &mut dc_apeerstate_t) {
|
||||
peerstate.last_seen = 0i32 as time_t;
|
||||
peerstate.last_seen_autocrypt = 0i32 as time_t;
|
||||
peerstate.prefer_encrypt = 0i32;
|
||||
peerstate.to_save = 0i32;
|
||||
free(peerstate.addr as *mut libc::c_void);
|
||||
peerstate.addr = 0 as *mut libc::c_char;
|
||||
free(peerstate.public_key_fingerprint as *mut libc::c_void);
|
||||
peerstate.public_key_fingerprint = 0 as *mut libc::c_char;
|
||||
free(peerstate.gossip_key_fingerprint as *mut libc::c_void);
|
||||
peerstate.gossip_key_fingerprint = 0 as *mut libc::c_char;
|
||||
free(peerstate.verified_key_fingerprint as *mut libc::c_void);
|
||||
peerstate.verified_key_fingerprint = 0 as *mut libc::c_char;
|
||||
|
||||
peerstate.public_key = None;
|
||||
peerstate.gossip_timestamp = 0i32 as time_t;
|
||||
peerstate.gossip_key = None;
|
||||
peerstate.verified_key = None;
|
||||
peerstate.degrade_event = 0i32;
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_init_from_header(
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
header: &Aheader,
|
||||
message_time: time_t,
|
||||
) -> libc::c_int {
|
||||
dc_apeerstate_empty(peerstate);
|
||||
peerstate.addr = dc_strdup(CString::new(header.addr.clone()).unwrap().as_ptr());
|
||||
peerstate.last_seen = message_time;
|
||||
peerstate.last_seen_autocrypt = message_time;
|
||||
peerstate.to_save |= 0x2i32;
|
||||
peerstate.prefer_encrypt = header.prefer_encrypt.to_i32().unwrap();
|
||||
peerstate.public_key = Some(header.public_key.clone());
|
||||
dc_apeerstate_recalc_fingerprint(peerstate);
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_recalc_fingerprint(peerstate: &mut dc_apeerstate_t) -> libc::c_int {
|
||||
let mut old_public_fingerprint: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut old_gossip_fingerprint: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
|
||||
if let Some(ref public_key) = peerstate.public_key {
|
||||
old_public_fingerprint = peerstate.public_key_fingerprint;
|
||||
peerstate.public_key_fingerprint = public_key.fingerprint_c();
|
||||
if old_public_fingerprint.is_null()
|
||||
|| *old_public_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| peerstate.public_key_fingerprint.is_null()
|
||||
|| *peerstate.public_key_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| strcasecmp(old_public_fingerprint, peerstate.public_key_fingerprint) != 0i32
|
||||
{
|
||||
peerstate.to_save |= 0x2i32;
|
||||
if !old_public_fingerprint.is_null()
|
||||
&& 0 != *old_public_fingerprint.offset(0isize) as libc::c_int
|
||||
{
|
||||
peerstate.degrade_event |= 0x2i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref gossip_key) = peerstate.gossip_key {
|
||||
old_gossip_fingerprint = peerstate.gossip_key_fingerprint;
|
||||
peerstate.gossip_key_fingerprint = gossip_key.fingerprint_c();
|
||||
|
||||
if old_gossip_fingerprint.is_null()
|
||||
|| *old_gossip_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| peerstate.gossip_key_fingerprint.is_null()
|
||||
|| *peerstate.gossip_key_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| strcasecmp(old_gossip_fingerprint, peerstate.gossip_key_fingerprint) != 0i32
|
||||
{
|
||||
peerstate.to_save |= 0x2i32;
|
||||
if !old_gossip_fingerprint.is_null()
|
||||
&& 0 != *old_gossip_fingerprint.offset(0isize) as libc::c_int
|
||||
{
|
||||
peerstate.degrade_event |= 0x2i32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(old_public_fingerprint as *mut libc::c_void);
|
||||
free(old_gossip_fingerprint as *mut libc::c_void);
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_init_from_gossip(
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
gossip_header: &Aheader,
|
||||
message_time: time_t,
|
||||
) -> libc::c_int {
|
||||
dc_apeerstate_empty(peerstate);
|
||||
peerstate.addr = dc_strdup(CString::new(gossip_header.addr.clone()).unwrap().as_ptr());
|
||||
peerstate.gossip_timestamp = message_time;
|
||||
peerstate.to_save |= 0x2i32;
|
||||
peerstate.gossip_key = Some(gossip_header.public_key.clone());
|
||||
dc_apeerstate_recalc_fingerprint(peerstate);
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_degrade_encryption(
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
message_time: time_t,
|
||||
) -> libc::c_int {
|
||||
if peerstate.prefer_encrypt == 1i32 {
|
||||
peerstate.degrade_event |= 0x1i32
|
||||
}
|
||||
peerstate.prefer_encrypt = 20i32;
|
||||
peerstate.last_seen = message_time;
|
||||
peerstate.to_save |= 0x2i32;
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_apply_header(
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
header: &Aheader,
|
||||
message_time: time_t,
|
||||
) {
|
||||
if peerstate.addr.is_null()
|
||||
|| CStr::from_ptr(peerstate.addr)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_lowercase()
|
||||
!= header.addr.to_lowercase()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if message_time > peerstate.last_seen_autocrypt {
|
||||
peerstate.last_seen = message_time;
|
||||
peerstate.last_seen_autocrypt = message_time;
|
||||
peerstate.to_save |= 0x1i32;
|
||||
if (header.prefer_encrypt == EncryptPreference::Mutual
|
||||
|| header.prefer_encrypt == EncryptPreference::NoPreference)
|
||||
&& header.prefer_encrypt.to_i32().unwrap() != peerstate.prefer_encrypt
|
||||
{
|
||||
if peerstate.prefer_encrypt == 1i32
|
||||
&& header.prefer_encrypt != EncryptPreference::Mutual
|
||||
{
|
||||
peerstate.degrade_event |= 0x1i32
|
||||
}
|
||||
peerstate.prefer_encrypt = header.prefer_encrypt.to_i32().unwrap();
|
||||
peerstate.to_save |= 0x2i32
|
||||
}
|
||||
|
||||
if peerstate.public_key.as_ref() != Some(&header.public_key) {
|
||||
peerstate.public_key = Some(header.public_key.clone());
|
||||
dc_apeerstate_recalc_fingerprint(peerstate);
|
||||
peerstate.to_save |= 0x2i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_apply_gossip(
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
gossip_header: &Aheader,
|
||||
message_time: time_t,
|
||||
) {
|
||||
if peerstate.addr.is_null()
|
||||
|| CStr::from_ptr(peerstate.addr)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_lowercase()
|
||||
!= gossip_header.addr.to_lowercase()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if message_time > peerstate.gossip_timestamp {
|
||||
peerstate.gossip_timestamp = message_time;
|
||||
peerstate.to_save |= 0x1i32;
|
||||
if peerstate.gossip_key.as_ref() != Some(&gossip_header.public_key) {
|
||||
peerstate.gossip_key = Some(gossip_header.public_key.clone());
|
||||
dc_apeerstate_recalc_fingerprint(peerstate);
|
||||
peerstate.to_save |= 0x2i32
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_render_gossip_header(
|
||||
peerstate: &dc_apeerstate_t,
|
||||
min_verified: libc::c_int,
|
||||
) -> *mut libc::c_char {
|
||||
if peerstate.addr.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let addr = CStr::from_ptr(peerstate.addr).to_str().unwrap().into();
|
||||
if let Some(key) = dc_apeerstate_peek_key(peerstate, min_verified) {
|
||||
// TODO: avoid cloning
|
||||
let header = Aheader::new(addr, key.clone(), EncryptPreference::NoPreference);
|
||||
let rendered = header.to_string();
|
||||
let rendered_c = CString::new(rendered).unwrap();
|
||||
return strdup(rendered_c.as_ptr());
|
||||
}
|
||||
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_peek_key<'a>(
|
||||
peerstate: &'a dc_apeerstate_t<'a>,
|
||||
min_verified: libc::c_int,
|
||||
) -> Option<&'a Key> {
|
||||
if peerstate.public_key.is_none()
|
||||
&& peerstate.gossip_key.is_none()
|
||||
&& peerstate.verified_key.is_none()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
if 0 != min_verified {
|
||||
return peerstate.verified_key.as_ref();
|
||||
}
|
||||
if peerstate.public_key.is_some() {
|
||||
return peerstate.public_key.as_ref();
|
||||
}
|
||||
|
||||
peerstate.gossip_key.as_ref()
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_set_verified(
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
which_key: libc::c_int,
|
||||
fingerprint: *const libc::c_char,
|
||||
verified: libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0;
|
||||
if !(which_key != 0 && which_key != 1 || verified != 2) {
|
||||
if which_key == 1
|
||||
&& !peerstate.public_key_fingerprint.is_null()
|
||||
&& *peerstate.public_key_fingerprint.offset(0isize) as libc::c_int != 0
|
||||
&& *fingerprint.offset(0isize) as libc::c_int != 0
|
||||
&& strcasecmp(peerstate.public_key_fingerprint, fingerprint) == 0
|
||||
{
|
||||
peerstate.to_save |= 0x2;
|
||||
peerstate.verified_key = peerstate.public_key.clone();
|
||||
peerstate.verified_key_fingerprint = dc_strdup(peerstate.public_key_fingerprint);
|
||||
success = 1
|
||||
}
|
||||
if which_key == 0
|
||||
&& !peerstate.gossip_key_fingerprint.is_null()
|
||||
&& *peerstate.gossip_key_fingerprint.offset(0isize) as libc::c_int != 0
|
||||
&& *fingerprint.offset(0isize) as libc::c_int != 0
|
||||
&& strcasecmp(peerstate.gossip_key_fingerprint, fingerprint) == 0
|
||||
{
|
||||
peerstate.to_save |= 0x2;
|
||||
peerstate.verified_key = peerstate.gossip_key.clone();
|
||||
peerstate.verified_key_fingerprint = dc_strdup(peerstate.gossip_key_fingerprint);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_load_by_addr(
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
sql: &dc_sqlite3_t,
|
||||
addr: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if !addr.is_null() {
|
||||
dc_apeerstate_empty(peerstate);
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
peerstate.context,
|
||||
sql,
|
||||
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_text(stmt, 1, addr, -1, None);
|
||||
if !(sqlite3_step(stmt) != 100) {
|
||||
dc_apeerstate_set_from_stmt(peerstate, stmt);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
success
|
||||
}
|
||||
|
||||
unsafe fn dc_apeerstate_set_from_stmt(
|
||||
mut peerstate: &mut dc_apeerstate_t,
|
||||
stmt: *mut sqlite3_stmt,
|
||||
) {
|
||||
peerstate.addr = dc_strdup(sqlite3_column_text(stmt, 0) as *mut libc::c_char);
|
||||
peerstate.last_seen = sqlite3_column_int64(stmt, 1) as time_t;
|
||||
peerstate.last_seen_autocrypt = sqlite3_column_int64(stmt, 2) as time_t;
|
||||
peerstate.prefer_encrypt = sqlite3_column_int(stmt, 3);
|
||||
peerstate.gossip_timestamp = sqlite3_column_int(stmt, 5) as time_t;
|
||||
peerstate.public_key_fingerprint = dc_strdup(sqlite3_column_text(stmt, 7) as *mut libc::c_char);
|
||||
peerstate.gossip_key_fingerprint = dc_strdup(sqlite3_column_text(stmt, 8) as *mut libc::c_char);
|
||||
peerstate.verified_key_fingerprint =
|
||||
dc_strdup(sqlite3_column_text(stmt, 10) as *mut libc::c_char);
|
||||
|
||||
if sqlite3_column_type(stmt, 4) != 5 {
|
||||
peerstate.public_key = Key::from_stmt(stmt, 4, KeyType::Public);
|
||||
}
|
||||
if sqlite3_column_type(stmt, 6) != 5 {
|
||||
peerstate.gossip_key = Key::from_stmt(stmt, 6, KeyType::Public);
|
||||
}
|
||||
if sqlite3_column_type(stmt, 9) != 5 {
|
||||
peerstate.verified_key = Key::from_stmt(stmt, 9, KeyType::Public);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_load_by_fingerprint(
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
sql: &dc_sqlite3_t,
|
||||
fingerprint: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if !fingerprint.is_null() {
|
||||
dc_apeerstate_empty(peerstate);
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
peerstate.context,
|
||||
sql,
|
||||
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE public_key_fingerprint=? COLLATE NOCASE OR gossip_key_fingerprint=? COLLATE NOCASE ORDER BY public_key_fingerprint=? DESC;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_text(stmt, 1, fingerprint, -1, None);
|
||||
sqlite3_bind_text(stmt, 2, fingerprint, -1, None);
|
||||
sqlite3_bind_text(stmt, 3, fingerprint, -1, None);
|
||||
if sqlite3_step(stmt) == 100 {
|
||||
dc_apeerstate_set_from_stmt(peerstate, stmt);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
success
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_save_to_db(
|
||||
peerstate: &dc_apeerstate_t,
|
||||
sql: &dc_sqlite3_t,
|
||||
create: libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let current_block: u64;
|
||||
let mut success: libc::c_int = 0;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if peerstate.addr.is_null() {
|
||||
return 0;
|
||||
}
|
||||
if 0 != create {
|
||||
stmt = dc_sqlite3_prepare(
|
||||
peerstate.context,
|
||||
sql,
|
||||
b"INSERT INTO acpeerstates (addr) VALUES(?);\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_text(stmt, 1, peerstate.addr, -1, None);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = 0 as *mut sqlite3_stmt
|
||||
}
|
||||
if 0 != peerstate.to_save & 0x2 || 0 != create {
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
peerstate.context,sql,
|
||||
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, prefer_encrypted=?, public_key=?, gossip_timestamp=?, gossip_key=?, public_key_fingerprint=?, gossip_key_fingerprint=?, verified_key=?, verified_key_fingerprint=? WHERE addr=?;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_int64(stmt, 1, peerstate.last_seen as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 2, peerstate.last_seen_autocrypt as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 3, peerstate.prefer_encrypt as sqlite3_int64);
|
||||
|
||||
let pub_bytes = peerstate.public_key.as_ref().map(|k| k.to_bytes());
|
||||
let gossip_bytes = peerstate.gossip_key.as_ref().map(|k| k.to_bytes());
|
||||
let ver_bytes = peerstate.verified_key.as_ref().map(|k| k.to_bytes());
|
||||
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
4,
|
||||
pub_bytes
|
||||
.as_ref()
|
||||
.map(|b| b.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()) as *const _,
|
||||
pub_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
|
||||
None,
|
||||
);
|
||||
|
||||
sqlite3_bind_int64(stmt, 5, peerstate.gossip_timestamp as sqlite3_int64);
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
6,
|
||||
gossip_bytes
|
||||
.as_ref()
|
||||
.map(|b| b.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()) as *const _,
|
||||
gossip_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
|
||||
None,
|
||||
);
|
||||
sqlite3_bind_text(stmt, 7, peerstate.public_key_fingerprint, -1, None);
|
||||
sqlite3_bind_text(stmt, 8, peerstate.gossip_key_fingerprint, -1, None);
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
9,
|
||||
ver_bytes
|
||||
.as_ref()
|
||||
.map(|b| b.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()) as *const _,
|
||||
ver_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
|
||||
None,
|
||||
);
|
||||
|
||||
sqlite3_bind_text(stmt, 10, peerstate.verified_key_fingerprint, -1, None);
|
||||
sqlite3_bind_text(stmt, 11, peerstate.addr, -1, None);
|
||||
if sqlite3_step(stmt) != 101 {
|
||||
current_block = 7258450500457619456;
|
||||
} else {
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = 0 as *mut sqlite3_stmt;
|
||||
current_block = 11913429853522160501;
|
||||
}
|
||||
} else if 0 != peerstate.to_save & 0x1 {
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
peerstate.context,sql,
|
||||
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? WHERE addr=?;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_int64(stmt, 1, peerstate.last_seen as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 2, peerstate.last_seen_autocrypt as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 3, peerstate.gossip_timestamp as sqlite3_int64);
|
||||
sqlite3_bind_text(stmt, 4, peerstate.addr, -1, None);
|
||||
if sqlite3_step(stmt) != 101 {
|
||||
current_block = 7258450500457619456;
|
||||
} else {
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = 0 as *mut sqlite3_stmt;
|
||||
current_block = 11913429853522160501;
|
||||
}
|
||||
} else {
|
||||
current_block = 11913429853522160501;
|
||||
}
|
||||
match current_block {
|
||||
11913429853522160501 => {
|
||||
if 0 != peerstate.to_save & 0x2 || 0 != create {
|
||||
dc_reset_gossiped_timestamp(peerstate.context, 0 as uint32_t);
|
||||
}
|
||||
success = 1
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_has_verified_key(
|
||||
peerstate: &dc_apeerstate_t,
|
||||
fingerprints: *const dc_hash_t,
|
||||
) -> bool {
|
||||
if fingerprints.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if peerstate.verified_key.is_some()
|
||||
&& !peerstate.verified_key_fingerprint.is_null()
|
||||
&& !dc_hash_find(
|
||||
fingerprints,
|
||||
peerstate.verified_key_fingerprint as *const libc::c_void,
|
||||
strlen(peerstate.verified_key_fingerprint) as libc::c_int,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::constants::Event;
|
||||
use crate::dc_apeerstate::*;
|
||||
use crate::dc_aheader::EncryptPreference;
|
||||
use crate::dc_array::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
use crate::dc_context::*;
|
||||
@@ -11,6 +11,7 @@ use crate::dc_sqlite3::*;
|
||||
use crate::dc_stock::*;
|
||||
use crate::dc_strbuilder::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
@@ -769,7 +770,6 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
let mut ret: dc_strbuilder_t;
|
||||
let loginparam: *mut dc_loginparam_t = dc_loginparam_new();
|
||||
let contact: *mut dc_contact_t = dc_contact_new(context);
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
|
||||
let mut fingerprint_self: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut fingerprint_other_verified: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
@@ -784,10 +784,10 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
};
|
||||
dc_strbuilder_init(&mut ret, 0i32);
|
||||
if !(!dc_contact_load_from_db(contact, &context.sql.clone().read().unwrap(), contact_id)) {
|
||||
dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
let peerstate = Peerstate::from_addr(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
(*contact).addr,
|
||||
to_str((*contact).addr),
|
||||
);
|
||||
dc_loginparam_read(
|
||||
context,
|
||||
@@ -800,10 +800,12 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
(*loginparam).addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
);
|
||||
if dc_apeerstate_peek_key(&peerstate, 0).is_some() {
|
||||
|
||||
if peerstate.is_some() && peerstate.as_ref().and_then(|p| p.peek_key(0)).is_some() {
|
||||
let peerstate = peerstate.as_ref().unwrap();
|
||||
p = dc_stock_str(
|
||||
context,
|
||||
if peerstate.prefer_encrypt == 1i32 {
|
||||
if peerstate.prefer_encrypt == EncryptPreference::Mutual {
|
||||
34i32
|
||||
} else {
|
||||
25i32
|
||||
@@ -828,29 +830,38 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
fingerprint_self = self_key
|
||||
.map(|k| k.formatted_fingerprint_c())
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
fingerprint_other_verified = dc_apeerstate_peek_key(&peerstate, 2)
|
||||
fingerprint_other_verified = peerstate
|
||||
.peek_key(2)
|
||||
.map(|k| k.formatted_fingerprint_c())
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
fingerprint_other_unverified = dc_apeerstate_peek_key(&peerstate, 0)
|
||||
fingerprint_other_unverified = peerstate
|
||||
.peek_key(0)
|
||||
.map(|k| k.formatted_fingerprint_c())
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
if strcmp((*loginparam).addr, peerstate.addr) < 0i32 {
|
||||
if peerstate.addr.is_some()
|
||||
&& to_str((*loginparam).addr) < peerstate.addr.as_ref().unwrap()
|
||||
{
|
||||
cat_fingerprint(
|
||||
&mut ret,
|
||||
(*loginparam).addr,
|
||||
fingerprint_self,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let c_addr = to_cstring(peerstate.addr.as_ref().unwrap());
|
||||
cat_fingerprint(
|
||||
&mut ret,
|
||||
peerstate.addr,
|
||||
c_addr.as_ptr(),
|
||||
fingerprint_other_verified,
|
||||
fingerprint_other_unverified,
|
||||
);
|
||||
} else {
|
||||
let c_addr = peerstate.addr.as_ref().map(to_cstring);
|
||||
|
||||
cat_fingerprint(
|
||||
&mut ret,
|
||||
peerstate.addr,
|
||||
c_addr
|
||||
.map(|a| a.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()),
|
||||
fingerprint_other_verified,
|
||||
fingerprint_other_unverified,
|
||||
);
|
||||
@@ -874,7 +885,6 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
}
|
||||
}
|
||||
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
dc_contact_unref(contact);
|
||||
dc_loginparam_unref(loginparam);
|
||||
|
||||
@@ -1094,7 +1104,7 @@ pub unsafe fn dc_contact_is_verified(contact: *mut dc_contact_t) -> libc::c_int
|
||||
/// If you do not have the peerstate available, it is loaded automatically.
|
||||
pub unsafe fn dc_contact_is_verified_ex<'a>(
|
||||
contact: *mut dc_contact_t<'a>,
|
||||
peerstate: Option<&dc_apeerstate_t<'a>>,
|
||||
peerstate: Option<&Peerstate<'a>>,
|
||||
) -> libc::c_int {
|
||||
if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint {
|
||||
return 0;
|
||||
@@ -1107,21 +1117,20 @@ pub unsafe fn dc_contact_is_verified_ex<'a>(
|
||||
}
|
||||
|
||||
if let Some(peerstate) = peerstate {
|
||||
if peerstate.verified_key.is_some() {
|
||||
if peerstate.verified_key().is_some() {
|
||||
2
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
let mut peerstate = dc_apeerstate_new((*contact).context);
|
||||
let peerstate = Peerstate::from_addr(
|
||||
(*contact).context,
|
||||
&(*contact).context.sql.clone().read().unwrap(),
|
||||
to_str((*contact).addr),
|
||||
);
|
||||
|
||||
let res = if 0
|
||||
!= dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
&(*contact).context.sql.clone().read().unwrap(),
|
||||
(*contact).addr,
|
||||
) {
|
||||
if peerstate.verified_key.is_some() {
|
||||
let res = if let Some(ps) = peerstate {
|
||||
if ps.verified_key().is_some() {
|
||||
2
|
||||
} else {
|
||||
0
|
||||
@@ -1129,7 +1138,6 @@ pub unsafe fn dc_contact_is_verified_ex<'a>(
|
||||
} else {
|
||||
0
|
||||
};
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
138
src/dc_e2ee.rs
138
src/dc_e2ee.rs
@@ -15,7 +15,6 @@ use mmime::mmapstring::*;
|
||||
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
|
||||
|
||||
use crate::dc_aheader::*;
|
||||
use crate::dc_apeerstate::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
use crate::dc_hash::*;
|
||||
use crate::dc_key::*;
|
||||
@@ -26,6 +25,7 @@ use crate::dc_pgp::*;
|
||||
use crate::dc_securejoin::*;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
@@ -62,7 +62,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
let imffields_unprotected: *mut mailimf_fields;
|
||||
let mut keyring = Keyring::default();
|
||||
let plain: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
let mut peerstates = Vec::new();
|
||||
let mut peerstates: Vec<Peerstate> = Vec::new();
|
||||
if !helper.is_null() {
|
||||
memset(
|
||||
helper as *mut libc::c_void,
|
||||
@@ -113,21 +113,23 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
0 as *mut libc::c_void
|
||||
})
|
||||
as *const libc::c_char;
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
if !(strcasecmp(recipient_addr, addr) == 0i32) {
|
||||
if 0 != dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
if strcasecmp(recipient_addr, addr) != 0 {
|
||||
let peerstate = Peerstate::from_addr(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
recipient_addr,
|
||||
) && (peerstate.prefer_encrypt == 1i32 || 0 != e2ee_guaranteed)
|
||||
to_str(recipient_addr),
|
||||
);
|
||||
if peerstate.is_some()
|
||||
&& (peerstate.as_ref().unwrap().prefer_encrypt
|
||||
== EncryptPreference::Mutual
|
||||
|| 0 != e2ee_guaranteed)
|
||||
{
|
||||
if let Some(key) = dc_apeerstate_peek_key(&peerstate, min_verified)
|
||||
{
|
||||
let peerstate = peerstate.unwrap();
|
||||
if let Some(key) = peerstate.peek_key(min_verified as usize) {
|
||||
keyring.add_owned(key.clone());
|
||||
peerstates.push(peerstate);
|
||||
}
|
||||
} else {
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
do_encrypt = 0i32;
|
||||
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
|
||||
break;
|
||||
@@ -183,11 +185,11 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
if iCnt > 1i32 {
|
||||
let mut i: libc::c_int = 0i32;
|
||||
while i < iCnt {
|
||||
let p: *mut libc::c_char = dc_apeerstate_render_gossip_header(
|
||||
&peerstates[i as usize],
|
||||
min_verified,
|
||||
);
|
||||
if !p.is_null() {
|
||||
let p = peerstates[i as usize]
|
||||
.render_gossip_header(min_verified as usize);
|
||||
|
||||
if p.is_some() {
|
||||
let header = to_cstring(p.unwrap());
|
||||
mailimf_fields_add(
|
||||
imffields_encrypted,
|
||||
mailimf_field_new_custom(
|
||||
@@ -195,7 +197,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
b"Autocrypt-Gossip\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
),
|
||||
p,
|
||||
strdup(header.as_ptr()),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -385,10 +387,6 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
if !plain.is_null() {
|
||||
mmap_string_free(plain);
|
||||
}
|
||||
|
||||
for peerstate in peerstates.iter_mut() {
|
||||
dc_apeerstate_unref(peerstate);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -583,8 +581,7 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
(to detect parts that could not be decrypted, simply look for left "multipart/encrypted" MIME types */
|
||||
/*just a pointer into mailmime structure, must not be freed*/
|
||||
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
|
||||
let mut message_time: time_t = 0i32 as time_t;
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
let mut message_time = 0;
|
||||
let mut from: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut private_keyring = Keyring::default();
|
||||
@@ -615,33 +612,26 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut peerstate = None;
|
||||
let autocryptheader = Aheader::from_imffields(from, imffields);
|
||||
if message_time > 0 && !from.is_null() {
|
||||
if 0 != dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
from,
|
||||
) {
|
||||
peerstate =
|
||||
Peerstate::from_addr(context, &context.sql.clone().read().unwrap(), to_str(from));
|
||||
|
||||
if let Some(ref mut peerstate) = peerstate {
|
||||
if let Some(ref header) = autocryptheader {
|
||||
dc_apeerstate_apply_header(&mut peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
0i32,
|
||||
);
|
||||
} else if message_time > peerstate.last_seen_autocrypt
|
||||
peerstate.apply_header(&header, message_time as u64);
|
||||
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
|
||||
} else if message_time as u64 > peerstate.last_seen_autocrypt
|
||||
&& 0 == contains_report(in_out_message)
|
||||
{
|
||||
dc_apeerstate_degrade_encryption(&mut peerstate, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
&peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
0i32,
|
||||
);
|
||||
peerstate.degrade_encryption(message_time as u64);
|
||||
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
|
||||
}
|
||||
} else if let Some(ref header) = autocryptheader {
|
||||
dc_apeerstate_init_from_header(&mut peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(&peerstate, &context.sql.clone().read().unwrap(), 1i32);
|
||||
let p = Peerstate::from_header(context, header, message_time as u64);
|
||||
p.save_to_db(&context.sql.clone().read().unwrap(), true);
|
||||
peerstate = Some(p);
|
||||
}
|
||||
}
|
||||
/* load private key for decryption */
|
||||
@@ -657,21 +647,23 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
self_addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
) {
|
||||
if peerstate.last_seen == 0 {
|
||||
dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
|
||||
peerstate = Peerstate::from_addr(
|
||||
&context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
from,
|
||||
to_str(from),
|
||||
);
|
||||
}
|
||||
if 0 != peerstate.degrade_event {
|
||||
dc_handle_degrade_event(context, &peerstate);
|
||||
}
|
||||
if let Some(ref key) = peerstate.gossip_key {
|
||||
public_keyring_for_validate.add_ref(key);
|
||||
}
|
||||
if let Some(ref key) = peerstate.public_key {
|
||||
public_keyring_for_validate.add_ref(key);
|
||||
if let Some(ref peerstate) = peerstate {
|
||||
if peerstate.degrade_event.is_some() {
|
||||
dc_handle_degrade_event(context, &peerstate);
|
||||
}
|
||||
if let Some(ref key) = peerstate.gossip_key {
|
||||
public_keyring_for_validate.add_ref(key);
|
||||
}
|
||||
if let Some(ref key) = peerstate.public_key {
|
||||
public_keyring_for_validate.add_ref(key);
|
||||
}
|
||||
}
|
||||
(*helper).signatures = malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
|
||||
dc_hash_init((*helper).signatures, 3i32, 1i32);
|
||||
@@ -706,7 +698,6 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
mailimf_fields_free(gossip_headers);
|
||||
}
|
||||
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
free(from as *mut libc::c_void);
|
||||
free(self_addr as *mut libc::c_void);
|
||||
}
|
||||
@@ -752,30 +743,25 @@ unsafe fn update_gossip_peerstates(
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
if 0 == dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
let mut peerstate = Peerstate::from_addr(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr(),
|
||||
) {
|
||||
dc_apeerstate_init_from_gossip(&mut peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
1i32,
|
||||
);
|
||||
&header.addr,
|
||||
);
|
||||
if let Some(ref mut peerstate) = peerstate {
|
||||
peerstate.apply_gossip(header, message_time as u64);
|
||||
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
|
||||
} else {
|
||||
dc_apeerstate_apply_gossip(&mut peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
0i32,
|
||||
);
|
||||
let p = Peerstate::from_gossip(context, header, message_time as u64);
|
||||
p.save_to_db(&context.sql.clone().read().unwrap(), true);
|
||||
peerstate = Some(p);
|
||||
}
|
||||
if 0 != peerstate.degrade_event {
|
||||
dc_handle_degrade_event(context, &peerstate);
|
||||
if let Some(peerstate) = peerstate {
|
||||
if peerstate.degrade_event.is_some() {
|
||||
dc_handle_degrade_event(context, &peerstate);
|
||||
}
|
||||
}
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
|
||||
if gossipped_addr.is_null() {
|
||||
gossipped_addr =
|
||||
malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::dc_log::*;
|
||||
use crate::dc_loginparam::*;
|
||||
use crate::dc_oauth2::dc_get_oauth2_access_token;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::dc_tools::{to_str, to_string};
|
||||
use crate::types::*;
|
||||
|
||||
pub const DC_IMAP_SEEN: usize = 0x0001;
|
||||
@@ -1698,14 +1699,6 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string(str: *const libc::c_char) -> String {
|
||||
unsafe { CStr::from_ptr(str).to_str().unwrap().to_string() }
|
||||
}
|
||||
|
||||
fn to_str<'a>(str: *const libc::c_char) -> &'a str {
|
||||
unsafe { CStr::from_ptr(str).to_str().unwrap() }
|
||||
}
|
||||
|
||||
/// Try to get the folder meaning by the name of the folder only used if the server does not support XLIST.
|
||||
// TODO: lots languages missing - maybe there is a list somewhere on other MUAs?
|
||||
// however, if we fail to find out the sent-folder,
|
||||
|
||||
23
src/dc_qr.rs
23
src/dc_qr.rs
@@ -1,4 +1,3 @@
|
||||
use crate::dc_apeerstate::*;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_contact::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
@@ -8,6 +7,7 @@ use crate::dc_lot::*;
|
||||
use crate::dc_param::*;
|
||||
use crate::dc_strencode::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
@@ -31,7 +31,6 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
|
||||
let mut name: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut invitenumber: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut auth: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
let mut qr_parsed: *mut dc_lot_t = dc_lot_new();
|
||||
let mut chat_id: uint32_t = 0i32 as uint32_t;
|
||||
let mut device_msg: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
@@ -238,17 +237,21 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
|
||||
16562876845594826114 => {}
|
||||
_ => {
|
||||
if !fingerprint.is_null() {
|
||||
let peerstate = Peerstate::from_fingerprint(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
to_str(fingerprint),
|
||||
);
|
||||
if addr.is_null() || invitenumber.is_null() || auth.is_null() {
|
||||
if 0 != dc_apeerstate_load_by_fingerprint(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
fingerprint,
|
||||
) {
|
||||
if let Some(peerstate) = peerstate {
|
||||
(*qr_parsed).state = 210i32;
|
||||
let c_addr = peerstate.addr.as_ref().map(to_cstring);
|
||||
(*qr_parsed).id = dc_add_or_lookup_contact(
|
||||
context,
|
||||
0 as *const libc::c_char,
|
||||
peerstate.addr,
|
||||
c_addr
|
||||
.map(|a| a.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()),
|
||||
0x80i32,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
@@ -324,7 +327,6 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
|
||||
}
|
||||
free(addr as *mut libc::c_void);
|
||||
free(fingerprint as *mut libc::c_void);
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
free(payload as *mut libc::c_void);
|
||||
free(name as *mut libc::c_void);
|
||||
free(invitenumber as *mut libc::c_void);
|
||||
@@ -332,5 +334,6 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
|
||||
free(device_msg as *mut libc::c_void);
|
||||
free(grpname as *mut libc::c_void);
|
||||
free(grpid as *mut libc::c_void);
|
||||
return qr_parsed;
|
||||
|
||||
qr_parsed
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::dc_apeerstate::*;
|
||||
use crate::dc_array::*;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_contact::*;
|
||||
@@ -27,6 +26,7 @@ use crate::dc_stock::*;
|
||||
use crate::dc_strbuilder::*;
|
||||
use crate::dc_strencode::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
@@ -1847,10 +1847,9 @@ unsafe fn check_verified_properties(
|
||||
to_ids: *const dc_array_t,
|
||||
failure_reason: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut current_block: u64 = 0;
|
||||
let mut everythings_okay: libc::c_int = 0i32;
|
||||
let contact: *mut dc_contact_t = dc_contact_new(context);
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
let mut to_ids_str: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut q3: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
@@ -1872,12 +1871,13 @@ unsafe fn check_verified_properties(
|
||||
// this check is skipped for SELF as there is no proper SELF-peerstate
|
||||
// and results in group-splits otherwise.
|
||||
if from_id != 1i32 as libc::c_uint {
|
||||
if 0 == dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
let peerstate = Peerstate::from_addr(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
(*contact).addr,
|
||||
) || dc_contact_is_verified_ex(contact, Some(&peerstate)) != 2i32
|
||||
{
|
||||
to_str((*contact).addr),
|
||||
);
|
||||
|
||||
if peerstate.is_none() || dc_contact_is_verified_ex(contact, peerstate.as_ref()) != 2 {
|
||||
*failure_reason = dc_mprintf(
|
||||
b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char,
|
||||
b"The sender of this message is not verified.\x00" as *const u8
|
||||
@@ -1885,17 +1885,16 @@ unsafe fn check_verified_properties(
|
||||
);
|
||||
dc_log_warning(context, 0i32, *failure_reason);
|
||||
current_block = 14837890932895028253;
|
||||
} else if !dc_apeerstate_has_verified_key(
|
||||
&peerstate,
|
||||
(*(*mimeparser).e2ee_helper).signatures,
|
||||
) {
|
||||
*failure_reason = dc_mprintf(
|
||||
b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char,
|
||||
b"The message was sent with non-verified encryption.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
dc_log_warning(context, 0i32, *failure_reason);
|
||||
current_block = 14837890932895028253;
|
||||
} else if let Some(peerstate) = peerstate {
|
||||
if !peerstate.has_verified_key((*(*mimeparser).e2ee_helper).signatures) {
|
||||
*failure_reason = dc_mprintf(
|
||||
b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char,
|
||||
b"The message was sent with non-verified encryption.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
dc_log_warning(context, 0i32, *failure_reason);
|
||||
current_block = 14837890932895028253;
|
||||
}
|
||||
} else {
|
||||
current_block = 15904375183555213903;
|
||||
}
|
||||
@@ -1920,27 +1919,26 @@ unsafe fn check_verified_properties(
|
||||
let to_addr: *const libc::c_char =
|
||||
sqlite3_column_text(stmt, 0i32) as *const libc::c_char;
|
||||
let mut is_verified: libc::c_int = sqlite3_column_int(stmt, 1i32);
|
||||
|
||||
let mut peerstate = Peerstate::from_addr(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
to_str(to_addr),
|
||||
);
|
||||
if !dc_hash_find(
|
||||
(*(*mimeparser).e2ee_helper).gossipped_addr,
|
||||
to_addr as *const libc::c_void,
|
||||
strlen(to_addr) as libc::c_int,
|
||||
)
|
||||
.is_null()
|
||||
&& 0 != dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
to_addr,
|
||||
)
|
||||
&& peerstate.is_some()
|
||||
{
|
||||
let peerstate = peerstate.as_mut().unwrap();
|
||||
if 0 == is_verified
|
||||
|| strcmp(
|
||||
peerstate.verified_key_fingerprint,
|
||||
peerstate.public_key_fingerprint,
|
||||
) != 0i32
|
||||
&& strcmp(
|
||||
peerstate.verified_key_fingerprint,
|
||||
peerstate.gossip_key_fingerprint,
|
||||
) != 0i32
|
||||
|| peerstate.verified_key_fingerprint
|
||||
!= peerstate.public_key_fingerprint
|
||||
&& peerstate.verified_key_fingerprint
|
||||
!= peerstate.gossip_key_fingerprint
|
||||
{
|
||||
dc_log_info(
|
||||
context,
|
||||
@@ -1949,14 +1947,12 @@ unsafe fn check_verified_properties(
|
||||
(*contact).addr,
|
||||
to_addr,
|
||||
);
|
||||
let fp = peerstate.gossip_key_fingerprint;
|
||||
dc_apeerstate_set_verified(&mut peerstate, 0i32, fp, 2i32);
|
||||
dc_apeerstate_save_to_db(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
0i32,
|
||||
);
|
||||
is_verified = 1i32
|
||||
let fp = peerstate.gossip_key_fingerprint.clone();
|
||||
if let Some(fp) = fp {
|
||||
peerstate.set_verified(0, &fp, 2);
|
||||
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
|
||||
is_verified = 1i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !(0 == is_verified) {
|
||||
@@ -1985,11 +1981,11 @@ unsafe fn check_verified_properties(
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
dc_contact_unref(contact);
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
free(to_ids_str as *mut libc::c_void);
|
||||
sqlite3_free(q3 as *mut libc::c_void);
|
||||
return everythings_okay;
|
||||
everythings_okay
|
||||
}
|
||||
|
||||
unsafe fn set_better_msg(mime_parser: *mut dc_mimeparser_t, better_msg: *mut *mut libc::c_char) {
|
||||
if !(*better_msg).is_null() && carray_count((*mime_parser).parts) > 0i32 as libc::c_uint {
|
||||
let mut part: *mut dc_mimepart_t =
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use mmime::mailimf_types::*;
|
||||
|
||||
use crate::constants::Event;
|
||||
use crate::dc_apeerstate::*;
|
||||
use crate::dc_aheader::EncryptPreference;
|
||||
use crate::dc_array::*;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_configure::*;
|
||||
@@ -21,6 +21,7 @@ use crate::dc_stock::*;
|
||||
use crate::dc_strencode::*;
|
||||
use crate::dc_token::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
@@ -353,27 +354,28 @@ unsafe fn fingerprint_equals_sender(
|
||||
let mut fingerprint_equal: libc::c_int = 0i32;
|
||||
let contacts: *mut dc_array_t = dc_get_chat_contacts(context, contact_chat_id);
|
||||
let contact: *mut dc_contact_t = dc_contact_new(context);
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
let mut fingerprint_normalized: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
|
||||
if !(dc_array_get_cnt(contacts) != 1) {
|
||||
let peerstate = Peerstate::from_addr(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
to_str((*contact).addr),
|
||||
);
|
||||
if !(!dc_contact_load_from_db(
|
||||
contact,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
dc_array_get_id(contacts, 0i32 as size_t),
|
||||
) || 0
|
||||
== dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
(*contact).addr,
|
||||
))
|
||||
) || peerstate.is_some())
|
||||
{
|
||||
fingerprint_normalized = dc_normalize_fingerprint_c(fingerprint);
|
||||
if strcasecmp(fingerprint_normalized, peerstate.public_key_fingerprint) == 0i32 {
|
||||
fingerprint_equal = 1i32
|
||||
let peerstate = peerstate.as_ref().unwrap();
|
||||
let fingerprint_normalized = dc_normalize_fingerprint(to_str(fingerprint));
|
||||
if peerstate.public_key_fingerprint.is_some()
|
||||
&& &fingerprint_normalized == peerstate.public_key_fingerprint.as_ref().unwrap()
|
||||
{
|
||||
fingerprint_equal = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(fingerprint_normalized as *mut libc::c_void);
|
||||
dc_contact_unref(contact);
|
||||
dc_array_unref(contacts);
|
||||
|
||||
@@ -973,23 +975,20 @@ unsafe fn mark_peer_as_verified(
|
||||
context: &dc_context_t,
|
||||
fingerprint: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
if !(0
|
||||
== dc_apeerstate_load_by_fingerprint(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
fingerprint,
|
||||
))
|
||||
{
|
||||
if !(0 == dc_apeerstate_set_verified(&mut peerstate, 1i32, fingerprint, 2i32)) {
|
||||
peerstate.prefer_encrypt = 1i32;
|
||||
peerstate.to_save |= 0x2i32;
|
||||
dc_apeerstate_save_to_db(&mut peerstate, &context.sql.clone().read().unwrap(), 0i32);
|
||||
success = 1i32
|
||||
let mut success = 0;
|
||||
|
||||
if let Some(ref mut peerstate) = Peerstate::from_fingerprint(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
to_str(fingerprint),
|
||||
) {
|
||||
if peerstate.set_verified(1, to_str(fingerprint), 2) {
|
||||
peerstate.prefer_encrypt = EncryptPreference::Mutual;
|
||||
peerstate.to_save = Some(ToSave::All);
|
||||
peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
|
||||
success = 1;
|
||||
}
|
||||
}
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
|
||||
success
|
||||
}
|
||||
@@ -1047,7 +1046,7 @@ unsafe fn encrypted_and_signed(
|
||||
1
|
||||
}
|
||||
|
||||
pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: &dc_apeerstate_t) {
|
||||
pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: &Peerstate) {
|
||||
let stmt;
|
||||
let contact_id: uint32_t;
|
||||
let mut contact_chat_id: uint32_t = 0i32 as uint32_t;
|
||||
@@ -1057,13 +1056,23 @@ pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: &dc_ape
|
||||
// together with DC_DE_FINGERPRINT_CHANGED which is logged, the idea is not to bother
|
||||
// with things they cannot fix, so the user is just kicked from the verified group
|
||||
// (and he will know this and can fix this)
|
||||
if 0 != peerstate.degrade_event & 0x2i32 {
|
||||
if Some(DegradeEvent::FingerprintChanged) == peerstate.degrade_event {
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"SELECT id FROM contacts WHERE addr=?;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_text(stmt, 1i32, peerstate.addr, -1i32, None);
|
||||
let c_addr = peerstate.addr.as_ref().map(to_cstring);
|
||||
sqlite3_bind_text(
|
||||
stmt,
|
||||
1i32,
|
||||
c_addr
|
||||
.as_ref()
|
||||
.map(|a| a.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()),
|
||||
-1i32,
|
||||
None,
|
||||
);
|
||||
sqlite3_step(stmt);
|
||||
contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t;
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -1075,7 +1084,13 @@ pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: &dc_ape
|
||||
&mut contact_chat_id,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
let msg: *mut libc::c_char = dc_stock_str_repl_string(context, 37i32, peerstate.addr);
|
||||
let msg = dc_stock_str_repl_string(
|
||||
context,
|
||||
37i32,
|
||||
c_addr
|
||||
.map(|a| a.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()),
|
||||
);
|
||||
dc_add_device_msg(context, contact_chat_id, msg);
|
||||
free(msg as *mut libc::c_void);
|
||||
(context.cb)(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use crate::constants::*;
|
||||
use crate::dc_apeerstate::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
use crate::dc_hash::*;
|
||||
use crate::dc_log::*;
|
||||
use crate::dc_param::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
@@ -906,16 +906,14 @@ pub unsafe fn dc_sqlite3_open(
|
||||
as *const libc::c_char,
|
||||
);
|
||||
while sqlite3_step(stmt) == 100 {
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
if 0 != dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
if let Some(ref mut peerstate) = Peerstate::from_addr(
|
||||
context,
|
||||
sql,
|
||||
sqlite3_column_text(stmt, 0) as *const libc::c_char,
|
||||
) && 0 != dc_apeerstate_recalc_fingerprint(&mut peerstate)
|
||||
{
|
||||
dc_apeerstate_save_to_db(&mut peerstate, sql, 0);
|
||||
to_str(sqlite3_column_text(stmt, 0) as *const libc::c_char),
|
||||
) {
|
||||
peerstate.recalc_fingerprint();
|
||||
peerstate.save_to_db(sql, false);
|
||||
}
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
@@ -1952,3 +1952,19 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_cstring<S: AsRef<str>>(s: S) -> std::ffi::CString {
|
||||
std::ffi::CString::new(s.as_ref()).unwrap()
|
||||
}
|
||||
|
||||
pub fn to_string(s: *const libc::c_char) -> String {
|
||||
if s.is_null() {
|
||||
return "".into();
|
||||
}
|
||||
unsafe { std::ffi::CStr::from_ptr(s).to_str().unwrap().to_string() }
|
||||
}
|
||||
|
||||
pub fn to_str<'a>(s: *const libc::c_char) -> &'a str {
|
||||
assert!(!s.is_null(), "cannot be used on null pointers");
|
||||
unsafe { std::ffi::CStr::from_ptr(s).to_str().unwrap() }
|
||||
}
|
||||
|
||||
11
src/lib.rs
11
src/lib.rs
@@ -22,9 +22,13 @@ extern crate smallvec;
|
||||
#[macro_use]
|
||||
pub mod dc_log;
|
||||
|
||||
pub mod dc_aheader;
|
||||
pub mod peerstate;
|
||||
pub mod types;
|
||||
pub mod x;
|
||||
|
||||
pub mod dc_apeerstate;
|
||||
pub mod constants;
|
||||
|
||||
pub mod dc_aheader;
|
||||
pub mod dc_array;
|
||||
pub mod dc_chat;
|
||||
pub mod dc_chatlist;
|
||||
@@ -64,8 +68,5 @@ pub mod dc_strbuilder;
|
||||
pub mod dc_strencode;
|
||||
pub mod dc_token;
|
||||
pub mod dc_tools;
|
||||
pub mod types;
|
||||
pub mod x;
|
||||
|
||||
pub mod constants;
|
||||
pub use self::constants::*;
|
||||
|
||||
564
src/peerstate.rs
Normal file
564
src/peerstate.rs
Normal file
@@ -0,0 +1,564 @@
|
||||
use std::ffi::CString;
|
||||
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::dc_aheader::*;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
use crate::dc_hash::*;
|
||||
use crate::dc_key::*;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::dc_tools::{to_cstring, to_string};
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
/// Peerstate represents the state of an Autocrypt peer.
|
||||
pub struct Peerstate<'a> {
|
||||
pub context: &'a dc_context_t,
|
||||
pub addr: Option<String>,
|
||||
pub last_seen: u64,
|
||||
pub last_seen_autocrypt: u64,
|
||||
pub prefer_encrypt: EncryptPreference,
|
||||
pub public_key: Option<Key>,
|
||||
pub public_key_fingerprint: Option<String>,
|
||||
pub gossip_key: Option<Key>,
|
||||
pub gossip_timestamp: u64,
|
||||
pub gossip_key_fingerprint: Option<String>,
|
||||
verified_key: VerifiedKey,
|
||||
pub verified_key_fingerprint: Option<String>,
|
||||
pub to_save: Option<ToSave>,
|
||||
pub degrade_event: Option<DegradeEvent>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum ToSave {
|
||||
Timestamps = 0x01,
|
||||
All = 0x02,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum DegradeEvent {
|
||||
/// Recoverable by an incoming encrypted mail.
|
||||
EncryptionPaused = 0x01,
|
||||
/// Recoverable by a new verify.
|
||||
FingerprintChanged = 0x02,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum VerifiedKey {
|
||||
Gossip,
|
||||
Public,
|
||||
None,
|
||||
}
|
||||
|
||||
impl Default for VerifiedKey {
|
||||
fn default() -> Self {
|
||||
VerifiedKey::None
|
||||
}
|
||||
}
|
||||
|
||||
impl VerifiedKey {
|
||||
pub fn is_none(&self) -> bool {
|
||||
match self {
|
||||
VerifiedKey::None => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_some(&self) -> bool {
|
||||
!self.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Peerstate<'a> {
|
||||
pub fn new(context: &'a dc_context_t) -> Self {
|
||||
Peerstate {
|
||||
context,
|
||||
addr: None,
|
||||
last_seen: 0,
|
||||
last_seen_autocrypt: 0,
|
||||
prefer_encrypt: Default::default(),
|
||||
public_key: None,
|
||||
public_key_fingerprint: None,
|
||||
gossip_key: None,
|
||||
gossip_key_fingerprint: None,
|
||||
gossip_timestamp: 0,
|
||||
verified_key: Default::default(),
|
||||
verified_key_fingerprint: None,
|
||||
to_save: None,
|
||||
degrade_event: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verified_key(&self) -> Option<&Key> {
|
||||
match self.verified_key {
|
||||
VerifiedKey::Public => self.public_key.as_ref(),
|
||||
VerifiedKey::Gossip => self.gossip_key.as_ref(),
|
||||
VerifiedKey::None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_header(context: &'a dc_context_t, header: &Aheader, message_time: u64) -> Self {
|
||||
let mut res = Self::new(context);
|
||||
|
||||
res.addr = Some(header.addr.clone());
|
||||
res.last_seen = message_time;
|
||||
res.last_seen_autocrypt = message_time;
|
||||
res.to_save = Some(ToSave::All);
|
||||
res.prefer_encrypt = header.prefer_encrypt;
|
||||
res.public_key = Some(header.public_key.clone());
|
||||
res.recalc_fingerprint();
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn from_gossip(
|
||||
context: &'a dc_context_t,
|
||||
gossip_header: &Aheader,
|
||||
message_time: u64,
|
||||
) -> Self {
|
||||
let mut res = Self::new(context);
|
||||
|
||||
res.addr = Some(gossip_header.addr.clone());
|
||||
res.gossip_timestamp = message_time;
|
||||
res.to_save = Some(ToSave::All);
|
||||
res.gossip_key = Some(gossip_header.public_key.clone());
|
||||
res.recalc_fingerprint();
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn from_addr(context: &'a dc_context_t, sql: &dc_sqlite3_t, addr: &str) -> Option<Self> {
|
||||
let mut res = None;
|
||||
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;\x00"
|
||||
as *const u8 as *const libc::c_char)
|
||||
};
|
||||
let addr_c = CString::new(addr.as_bytes()).unwrap();
|
||||
unsafe { sqlite3_bind_text(stmt, 1, addr_c.as_ptr(), -1, None) };
|
||||
if unsafe { sqlite3_step(stmt) } == 100 {
|
||||
res = Some(Self::from_stmt(context, stmt));
|
||||
}
|
||||
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
res
|
||||
}
|
||||
|
||||
pub fn from_fingerprint(
|
||||
context: &'a dc_context_t,
|
||||
sql: &dc_sqlite3_t,
|
||||
fingerprint: &str,
|
||||
) -> Option<Self> {
|
||||
let mut res = None;
|
||||
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE public_key_fingerprint=? COLLATE NOCASE OR gossip_key_fingerprint=? COLLATE NOCASE ORDER BY public_key_fingerprint=? DESC;\x00"
|
||||
as *const u8 as *const libc::c_char)
|
||||
};
|
||||
|
||||
let fp_c = CString::new(fingerprint.as_bytes()).unwrap();
|
||||
unsafe {
|
||||
sqlite3_bind_text(stmt, 1, fp_c.as_ptr(), -1, None);
|
||||
sqlite3_bind_text(stmt, 2, fp_c.as_ptr(), -1, None);
|
||||
sqlite3_bind_text(stmt, 3, fp_c.as_ptr(), -1, None);
|
||||
}
|
||||
if unsafe { sqlite3_step(stmt) == 100 } {
|
||||
res = Some(Self::from_stmt(context, stmt));
|
||||
}
|
||||
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn from_stmt(context: &'a dc_context_t, stmt: *mut sqlite3_stmt) -> Self {
|
||||
let mut res = Self::new(context);
|
||||
|
||||
res.addr = Some(to_string(unsafe {
|
||||
sqlite3_column_text(stmt, 0) as *const _
|
||||
}));
|
||||
res.last_seen = unsafe { sqlite3_column_int64(stmt, 1) } as u64;
|
||||
res.last_seen_autocrypt = unsafe { sqlite3_column_int64(stmt, 2) } as u64;
|
||||
res.prefer_encrypt =
|
||||
EncryptPreference::from_i32(unsafe { sqlite3_column_int(stmt, 3) }).unwrap_or_default();
|
||||
res.gossip_timestamp = unsafe { sqlite3_column_int(stmt, 5) } as u64;
|
||||
res.public_key_fingerprint = Some(to_string(unsafe {
|
||||
sqlite3_column_text(stmt, 7) as *const _
|
||||
}));
|
||||
res.gossip_key_fingerprint = Some(to_string(unsafe {
|
||||
sqlite3_column_text(stmt, 8) as *const _
|
||||
}));
|
||||
res.verified_key_fingerprint = Some(to_string(unsafe {
|
||||
sqlite3_column_text(stmt, 10) as *const _
|
||||
}));
|
||||
|
||||
if unsafe { sqlite3_column_type(stmt, 4) } != 5 {
|
||||
res.public_key = Key::from_stmt(stmt, 4, KeyType::Public);
|
||||
}
|
||||
if unsafe { sqlite3_column_type(stmt, 6) } != 5 {
|
||||
res.gossip_key = Key::from_stmt(stmt, 6, KeyType::Public);
|
||||
}
|
||||
if unsafe { sqlite3_column_type(stmt, 9) } != 5 {
|
||||
let vk = Key::from_stmt(stmt, 9, KeyType::Public);
|
||||
res.verified_key = if vk == res.gossip_key {
|
||||
VerifiedKey::Gossip
|
||||
} else if vk == res.public_key {
|
||||
VerifiedKey::Public
|
||||
} else {
|
||||
VerifiedKey::None
|
||||
};
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn recalc_fingerprint(&mut self) {
|
||||
if let Some(ref public_key) = self.public_key {
|
||||
let old_public_fingerprint = self.public_key_fingerprint.take();
|
||||
self.public_key_fingerprint = Some(public_key.fingerprint());
|
||||
|
||||
if old_public_fingerprint.is_none()
|
||||
|| self.public_key_fingerprint.is_none()
|
||||
|| old_public_fingerprint != self.public_key_fingerprint
|
||||
{
|
||||
self.to_save = Some(ToSave::All);
|
||||
if old_public_fingerprint.is_some() {
|
||||
self.degrade_event = Some(DegradeEvent::FingerprintChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref gossip_key) = self.gossip_key {
|
||||
let old_gossip_fingerprint = self.gossip_key_fingerprint.take();
|
||||
self.gossip_key_fingerprint = Some(gossip_key.fingerprint());
|
||||
|
||||
if old_gossip_fingerprint.is_none()
|
||||
|| self.gossip_key_fingerprint.is_none()
|
||||
|| old_gossip_fingerprint != self.gossip_key_fingerprint
|
||||
{
|
||||
self.to_save = Some(ToSave::All);
|
||||
if old_gossip_fingerprint.is_some() {
|
||||
self.degrade_event = Some(DegradeEvent::FingerprintChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn degrade_encryption(&mut self, message_time: u64) {
|
||||
if self.prefer_encrypt == EncryptPreference::Mutual {
|
||||
self.degrade_event = Some(DegradeEvent::EncryptionPaused);
|
||||
}
|
||||
|
||||
self.prefer_encrypt = EncryptPreference::Reset;
|
||||
self.last_seen = message_time;
|
||||
self.to_save = Some(ToSave::All);
|
||||
}
|
||||
|
||||
pub fn apply_header(&mut self, header: &Aheader, message_time: u64) {
|
||||
if self.addr.is_none()
|
||||
|| self.addr.as_ref().unwrap().to_lowercase() != header.addr.to_lowercase()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if message_time > self.last_seen_autocrypt {
|
||||
self.last_seen = message_time;
|
||||
self.last_seen_autocrypt = message_time;
|
||||
self.to_save = Some(ToSave::Timestamps);
|
||||
if (header.prefer_encrypt == EncryptPreference::Mutual
|
||||
|| header.prefer_encrypt == EncryptPreference::NoPreference)
|
||||
&& header.prefer_encrypt != self.prefer_encrypt
|
||||
{
|
||||
if self.prefer_encrypt == EncryptPreference::Mutual
|
||||
&& header.prefer_encrypt != EncryptPreference::Mutual
|
||||
{
|
||||
self.degrade_event = Some(DegradeEvent::EncryptionPaused);
|
||||
}
|
||||
self.prefer_encrypt = header.prefer_encrypt;
|
||||
self.to_save = Some(ToSave::All)
|
||||
}
|
||||
|
||||
if self.public_key.as_ref() != Some(&header.public_key) {
|
||||
self.public_key = Some(header.public_key.clone());
|
||||
self.recalc_fingerprint();
|
||||
self.to_save = Some(ToSave::All);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_gossip(&mut self, gossip_header: &Aheader, message_time: u64) {
|
||||
if self.addr.is_none()
|
||||
|| self.addr.as_ref().unwrap().to_lowercase() != gossip_header.addr.to_lowercase()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if message_time > self.gossip_timestamp {
|
||||
self.gossip_timestamp = message_time;
|
||||
self.to_save = Some(ToSave::Timestamps);
|
||||
if self.gossip_key.as_ref() != Some(&gossip_header.public_key) {
|
||||
self.gossip_key = Some(gossip_header.public_key.clone());
|
||||
self.recalc_fingerprint();
|
||||
self.to_save = Some(ToSave::All)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn render_gossip_header(&self, min_verified: usize) -> Option<String> {
|
||||
if let Some(ref addr) = self.addr {
|
||||
if let Some(key) = self.peek_key(min_verified) {
|
||||
// TODO: avoid cloning
|
||||
let header = Aheader::new(
|
||||
addr.to_string(),
|
||||
key.clone(),
|
||||
EncryptPreference::NoPreference,
|
||||
);
|
||||
return Some(header.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn peek_key(&self, min_verified: usize) -> Option<&Key> {
|
||||
if self.public_key.is_none() && self.gossip_key.is_none() && self.verified_key.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if 0 != min_verified {
|
||||
return self.verified_key();
|
||||
}
|
||||
if self.public_key.is_some() {
|
||||
return self.public_key.as_ref();
|
||||
}
|
||||
|
||||
self.gossip_key.as_ref()
|
||||
}
|
||||
|
||||
pub fn set_verified(&mut self, which_key: usize, fingerprint: &str, verified: usize) -> bool {
|
||||
let mut success = false;
|
||||
if !(which_key != 0 && which_key != 1 || verified != 2) {
|
||||
if which_key == 1
|
||||
&& self.public_key_fingerprint.is_some()
|
||||
&& self.public_key_fingerprint.as_ref().unwrap() == fingerprint
|
||||
{
|
||||
self.to_save = Some(ToSave::All);
|
||||
self.verified_key = VerifiedKey::Public;
|
||||
self.verified_key_fingerprint = self.public_key_fingerprint.clone();
|
||||
success = true;
|
||||
}
|
||||
if which_key == 0
|
||||
&& self.gossip_key_fingerprint.is_some()
|
||||
&& self.gossip_key_fingerprint.as_ref().unwrap() == fingerprint
|
||||
{
|
||||
self.to_save = Some(ToSave::All);
|
||||
self.verified_key = VerifiedKey::Gossip;
|
||||
self.verified_key_fingerprint = self.gossip_key_fingerprint.clone();
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
pub fn save_to_db(&self, sql: &dc_sqlite3_t, create: bool) -> bool {
|
||||
let mut success = false;
|
||||
|
||||
if self.addr.is_none() {
|
||||
return success;
|
||||
}
|
||||
|
||||
if create {
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
self.context,
|
||||
sql,
|
||||
b"INSERT INTO acpeerstates (addr) VALUES(?);\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
let addr_c = CString::new(self.addr.as_ref().unwrap().as_bytes()).unwrap();
|
||||
unsafe {
|
||||
sqlite3_bind_text(stmt, 1, addr_c.as_ptr(), -1, None);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
if self.to_save == Some(ToSave::All) || create {
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
self.context,sql,
|
||||
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, prefer_encrypted=?, public_key=?, gossip_timestamp=?, gossip_key=?, public_key_fingerprint=?, gossip_key_fingerprint=?, verified_key=?, verified_key_fingerprint=? WHERE addr=?;\x00"
|
||||
as *const u8 as *const libc::c_char)
|
||||
};
|
||||
|
||||
unsafe {
|
||||
sqlite3_bind_int64(stmt, 1, self.last_seen as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 2, self.last_seen_autocrypt as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 3, self.prefer_encrypt as sqlite3_int64);
|
||||
}
|
||||
|
||||
let addr_c = self.addr.as_ref().map(|addr| to_cstring(addr));
|
||||
let pub_bytes = self.public_key.as_ref().map(|k| k.to_bytes());
|
||||
let gossip_bytes = self.gossip_key.as_ref().map(|k| k.to_bytes());
|
||||
let ver_bytes = self.verified_key().map(|k| k.to_bytes());
|
||||
|
||||
unsafe {
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
4,
|
||||
pub_bytes
|
||||
.as_ref()
|
||||
.map(|b| b.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()) as *const _,
|
||||
pub_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
|
||||
None,
|
||||
);
|
||||
sqlite3_bind_int64(stmt, 5, self.gossip_timestamp as sqlite3_int64);
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
6,
|
||||
gossip_bytes
|
||||
.as_ref()
|
||||
.map(|b| b.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()) as *const _,
|
||||
gossip_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
|
||||
None,
|
||||
);
|
||||
let pkc = self
|
||||
.public_key_fingerprint
|
||||
.as_ref()
|
||||
.map(|fp| to_cstring(fp));
|
||||
let gkc = self
|
||||
.gossip_key_fingerprint
|
||||
.as_ref()
|
||||
.map(|fp| to_cstring(fp));
|
||||
|
||||
sqlite3_bind_text(
|
||||
stmt,
|
||||
7,
|
||||
pkc.map(|fp| fp.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()),
|
||||
-1,
|
||||
None,
|
||||
);
|
||||
sqlite3_bind_text(
|
||||
stmt,
|
||||
8,
|
||||
gkc.map(|fp| fp.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()),
|
||||
-1,
|
||||
None,
|
||||
);
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
9,
|
||||
ver_bytes
|
||||
.as_ref()
|
||||
.map(|b| b.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()) as *const _,
|
||||
ver_bytes.as_ref().map(|b| b.len()).unwrap_or_else(|| 0) as libc::c_int,
|
||||
None,
|
||||
);
|
||||
|
||||
let vkc = self
|
||||
.verified_key_fingerprint
|
||||
.as_ref()
|
||||
.map(|fp| to_cstring(fp));
|
||||
|
||||
sqlite3_bind_text(
|
||||
stmt,
|
||||
10,
|
||||
vkc.map(|fp| fp.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()),
|
||||
-1,
|
||||
None,
|
||||
);
|
||||
sqlite3_bind_text(
|
||||
stmt,
|
||||
11,
|
||||
addr_c
|
||||
.map(|addr| addr.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()),
|
||||
-1,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
if unsafe { sqlite3_step(stmt) } == 101 {
|
||||
success = true;
|
||||
}
|
||||
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
} else if self.to_save == Some(ToSave::Timestamps) {
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
self.context,sql,
|
||||
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? WHERE addr=?;\x00"
|
||||
as *const u8 as *const libc::c_char)
|
||||
};
|
||||
|
||||
let addr_c = self.addr.as_ref().map(|fp| to_cstring(fp));
|
||||
|
||||
unsafe {
|
||||
sqlite3_bind_int64(stmt, 1, self.last_seen as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 2, self.last_seen_autocrypt as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 3, self.gossip_timestamp as sqlite3_int64);
|
||||
sqlite3_bind_text(
|
||||
stmt,
|
||||
4,
|
||||
addr_c
|
||||
.map(|addr| addr.as_ptr())
|
||||
.unwrap_or_else(|| std::ptr::null()),
|
||||
-1,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
if unsafe { sqlite3_step(stmt) } == 101 {
|
||||
success = true;
|
||||
}
|
||||
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
}
|
||||
|
||||
if self.to_save == Some(ToSave::All) || create {
|
||||
unsafe { dc_reset_gossiped_timestamp(self.context, 0 as uint32_t) };
|
||||
}
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
pub fn has_verified_key(&self, fingerprints: *const dc_hash_t) -> bool {
|
||||
if fingerprints.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if self.verified_key.is_some() && self.verified_key_fingerprint.is_some() {
|
||||
let vkc = to_cstring(self.verified_key_fingerprint.as_ref().unwrap());
|
||||
if !unsafe {
|
||||
dc_hash_find(
|
||||
fingerprints,
|
||||
vkc.as_ptr() as *const libc::c_void,
|
||||
strlen(vkc.as_ptr()) as libc::c_int,
|
||||
)
|
||||
.is_null()
|
||||
} {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user