refactor(peerstate): safe implementation of peerstate

This commit is contained in:
Friedel Ziegelmayer
2019-05-26 22:33:39 +02:00
committed by GitHub
parent d926b3536d
commit 94aa314f30
13 changed files with 794 additions and 772 deletions

View File

@@ -3,7 +3,6 @@ use std::sync::{Arc, RwLock};
use deltachat::constants::*; use deltachat::constants::*;
use deltachat::dc_aheader::*; use deltachat::dc_aheader::*;
use deltachat::dc_apeerstate::*;
use deltachat::dc_array::*; use deltachat::dc_array::*;
use deltachat::dc_chat::*; use deltachat::dc_chat::*;
use deltachat::dc_chatlist::*; use deltachat::dc_chatlist::*;
@@ -44,6 +43,7 @@ use deltachat::dc_strbuilder::*;
use deltachat::dc_strencode::*; use deltachat::dc_strencode::*;
use deltachat::dc_token::*; use deltachat::dc_token::*;
use deltachat::dc_tools::*; use deltachat::dc_tools::*;
use deltachat::peerstate::*;
use deltachat::types::*; use deltachat::types::*;
use deltachat::x::*; use deltachat::x::*;
use num_traits::FromPrimitive; 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) { unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) {
let mut contact: *mut dc_contact_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) { if !dc_array_search_id(contacts, 1i32 as uint32_t, 0 as *mut size_t) {
dc_array_add_id(contacts, 1i32 as uint32_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 b"addr unset\x00" as *const u8 as *const libc::c_char
}, },
); );
let peerstate_ok: libc::c_int = dc_apeerstate_load_by_addr( let peerstate =
&mut peerstate, Peerstate::from_addr(context, &context.sql.clone().read().unwrap(), to_str(addr));
&context.sql.clone().read().unwrap(), if peerstate.is_some() && contact_id != 1i32 as libc::c_uint {
addr, let pe = to_cstring(format!("{}", peerstate.as_ref().unwrap().prefer_encrypt));
);
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,
)
}
}
line2 = dc_mprintf( line2 = dc_mprintf(
b", prefer-encrypt=%s\x00" as *const u8 as *const libc::c_char, 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); dc_contact_unref(contact);
free(name as *mut libc::c_void); 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 i += 1
} }
dc_apeerstate_unref(&mut peerstate);
} }
static mut s_is_auth: libc::c_int = 0i32; static mut s_is_auth: libc::c_int = 0i32;
pub unsafe fn dc_cmdline_skip_auth() { pub unsafe fn dc_cmdline_skip_auth() {

View File

@@ -22,7 +22,6 @@ use std::sync::{Arc, RwLock};
use deltachat::constants::*; use deltachat::constants::*;
use deltachat::dc_aheader::*; use deltachat::dc_aheader::*;
use deltachat::dc_apeerstate::*;
use deltachat::dc_array::*; use deltachat::dc_array::*;
use deltachat::dc_chat::*; use deltachat::dc_chat::*;
use deltachat::dc_chatlist::*; use deltachat::dc_chatlist::*;
@@ -63,6 +62,7 @@ use deltachat::dc_strbuilder::*;
use deltachat::dc_strencode::*; use deltachat::dc_strencode::*;
use deltachat::dc_token::*; use deltachat::dc_token::*;
use deltachat::dc_tools::*; use deltachat::dc_tools::*;
use deltachat::peerstate::*;
use deltachat::types::*; use deltachat::types::*;
use deltachat::x::*; use deltachat::x::*;
mod cmdline; mod cmdline;

View File

@@ -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
}

View File

@@ -1,5 +1,5 @@
use crate::constants::Event; use crate::constants::Event;
use crate::dc_apeerstate::*; use crate::dc_aheader::EncryptPreference;
use crate::dc_array::*; use crate::dc_array::*;
use crate::dc_context::dc_context_t; use crate::dc_context::dc_context_t;
use crate::dc_context::*; use crate::dc_context::*;
@@ -11,6 +11,7 @@ use crate::dc_sqlite3::*;
use crate::dc_stock::*; use crate::dc_stock::*;
use crate::dc_strbuilder::*; use crate::dc_strbuilder::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*; use crate::types::*;
use crate::x::*; use crate::x::*;
@@ -769,7 +770,6 @@ pub unsafe fn dc_get_contact_encrinfo(
let mut ret: dc_strbuilder_t; let mut ret: dc_strbuilder_t;
let loginparam: *mut dc_loginparam_t = dc_loginparam_new(); let loginparam: *mut dc_loginparam_t = dc_loginparam_new();
let contact: *mut dc_contact_t = dc_contact_new(context); 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_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; 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); dc_strbuilder_init(&mut ret, 0i32);
if !(!dc_contact_load_from_db(contact, &context.sql.clone().read().unwrap(), contact_id)) { if !(!dc_contact_load_from_db(contact, &context.sql.clone().read().unwrap(), contact_id)) {
dc_apeerstate_load_by_addr( let peerstate = Peerstate::from_addr(
&mut peerstate, context,
&context.sql.clone().read().unwrap(), &context.sql.clone().read().unwrap(),
(*contact).addr, to_str((*contact).addr),
); );
dc_loginparam_read( dc_loginparam_read(
context, context,
@@ -800,10 +800,12 @@ pub unsafe fn dc_get_contact_encrinfo(
(*loginparam).addr, (*loginparam).addr,
&context.sql.clone().read().unwrap(), &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( p = dc_stock_str(
context, context,
if peerstate.prefer_encrypt == 1i32 { if peerstate.prefer_encrypt == EncryptPreference::Mutual {
34i32 34i32
} else { } else {
25i32 25i32
@@ -828,29 +830,38 @@ pub unsafe fn dc_get_contact_encrinfo(
fingerprint_self = self_key fingerprint_self = self_key
.map(|k| k.formatted_fingerprint_c()) .map(|k| k.formatted_fingerprint_c())
.unwrap_or(std::ptr::null_mut()); .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()) .map(|k| k.formatted_fingerprint_c())
.unwrap_or(std::ptr::null_mut()); .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()) .map(|k| k.formatted_fingerprint_c())
.unwrap_or(std::ptr::null_mut()); .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( cat_fingerprint(
&mut ret, &mut ret,
(*loginparam).addr, (*loginparam).addr,
fingerprint_self, fingerprint_self,
0 as *const libc::c_char, 0 as *const libc::c_char,
); );
let c_addr = to_cstring(peerstate.addr.as_ref().unwrap());
cat_fingerprint( cat_fingerprint(
&mut ret, &mut ret,
peerstate.addr, c_addr.as_ptr(),
fingerprint_other_verified, fingerprint_other_verified,
fingerprint_other_unverified, fingerprint_other_unverified,
); );
} else { } else {
let c_addr = peerstate.addr.as_ref().map(to_cstring);
cat_fingerprint( cat_fingerprint(
&mut ret, &mut ret,
peerstate.addr, c_addr
.map(|a| a.as_ptr())
.unwrap_or_else(|| std::ptr::null()),
fingerprint_other_verified, fingerprint_other_verified,
fingerprint_other_unverified, fingerprint_other_unverified,
); );
@@ -874,7 +885,6 @@ pub unsafe fn dc_get_contact_encrinfo(
} }
} }
dc_apeerstate_unref(&mut peerstate);
dc_contact_unref(contact); dc_contact_unref(contact);
dc_loginparam_unref(loginparam); 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. /// If you do not have the peerstate available, it is loaded automatically.
pub unsafe fn dc_contact_is_verified_ex<'a>( pub unsafe fn dc_contact_is_verified_ex<'a>(
contact: *mut dc_contact_t<'a>, contact: *mut dc_contact_t<'a>,
peerstate: Option<&dc_apeerstate_t<'a>>, peerstate: Option<&Peerstate<'a>>,
) -> libc::c_int { ) -> libc::c_int {
if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint {
return 0; return 0;
@@ -1107,21 +1117,20 @@ pub unsafe fn dc_contact_is_verified_ex<'a>(
} }
if let Some(peerstate) = peerstate { if let Some(peerstate) = peerstate {
if peerstate.verified_key.is_some() { if peerstate.verified_key().is_some() {
2 2
} else { } else {
0 0
} }
} else { } 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 let res = if let Some(ps) = peerstate {
!= dc_apeerstate_load_by_addr( if ps.verified_key().is_some() {
&mut peerstate,
&(*contact).context.sql.clone().read().unwrap(),
(*contact).addr,
) {
if peerstate.verified_key.is_some() {
2 2
} else { } else {
0 0
@@ -1129,7 +1138,6 @@ pub unsafe fn dc_contact_is_verified_ex<'a>(
} else { } else {
0 0
}; };
dc_apeerstate_unref(&mut peerstate);
res res
} }

View File

@@ -15,7 +15,6 @@ use mmime::mmapstring::*;
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR}; use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
use crate::dc_aheader::*; use crate::dc_aheader::*;
use crate::dc_apeerstate::*;
use crate::dc_context::dc_context_t; use crate::dc_context::dc_context_t;
use crate::dc_hash::*; use crate::dc_hash::*;
use crate::dc_key::*; use crate::dc_key::*;
@@ -26,6 +25,7 @@ use crate::dc_pgp::*;
use crate::dc_securejoin::*; use crate::dc_securejoin::*;
use crate::dc_sqlite3::*; use crate::dc_sqlite3::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*; use crate::types::*;
use crate::x::*; use crate::x::*;
@@ -62,7 +62,7 @@ pub unsafe fn dc_e2ee_encrypt(
let imffields_unprotected: *mut mailimf_fields; let imffields_unprotected: *mut mailimf_fields;
let mut keyring = Keyring::default(); let mut keyring = Keyring::default();
let plain: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char); 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() { if !helper.is_null() {
memset( memset(
helper as *mut libc::c_void, helper as *mut libc::c_void,
@@ -113,21 +113,23 @@ pub unsafe fn dc_e2ee_encrypt(
0 as *mut libc::c_void 0 as *mut libc::c_void
}) })
as *const libc::c_char; as *const libc::c_char;
let mut peerstate = dc_apeerstate_new(context); if strcasecmp(recipient_addr, addr) != 0 {
if !(strcasecmp(recipient_addr, addr) == 0i32) { let peerstate = Peerstate::from_addr(
if 0 != dc_apeerstate_load_by_addr( context,
&mut peerstate,
&context.sql.clone().read().unwrap(), &context.sql.clone().read().unwrap(),
recipient_addr, to_str(recipient_addr),
) && (peerstate.prefer_encrypt == 1i32 || 0 != e2ee_guaranteed) );
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()); keyring.add_owned(key.clone());
peerstates.push(peerstate); peerstates.push(peerstate);
} }
} else { } else {
dc_apeerstate_unref(&mut peerstate);
do_encrypt = 0i32; do_encrypt = 0i32;
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */ /* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
break; break;
@@ -183,11 +185,11 @@ pub unsafe fn dc_e2ee_encrypt(
if iCnt > 1i32 { if iCnt > 1i32 {
let mut i: libc::c_int = 0i32; let mut i: libc::c_int = 0i32;
while i < iCnt { while i < iCnt {
let p: *mut libc::c_char = dc_apeerstate_render_gossip_header( let p = peerstates[i as usize]
&peerstates[i as usize], .render_gossip_header(min_verified as usize);
min_verified,
); if p.is_some() {
if !p.is_null() { let header = to_cstring(p.unwrap());
mailimf_fields_add( mailimf_fields_add(
imffields_encrypted, imffields_encrypted,
mailimf_field_new_custom( mailimf_field_new_custom(
@@ -195,7 +197,7 @@ pub unsafe fn dc_e2ee_encrypt(
b"Autocrypt-Gossip\x00" as *const u8 b"Autocrypt-Gossip\x00" as *const u8
as *const libc::c_char, as *const libc::c_char,
), ),
p, strdup(header.as_ptr()),
), ),
); );
} }
@@ -385,10 +387,6 @@ pub unsafe fn dc_e2ee_encrypt(
if !plain.is_null() { if !plain.is_null() {
mmap_string_free(plain); 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 */ (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*/ /*just a pointer into mailmime structure, must not be freed*/
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message); let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
let mut message_time: time_t = 0i32 as time_t; let mut message_time = 0;
let mut peerstate = dc_apeerstate_new(context);
let mut from: *mut libc::c_char = 0 as *mut libc::c_char; 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 self_addr: *mut libc::c_char = 0 as *mut libc::c_char;
let mut private_keyring = Keyring::default(); 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); let autocryptheader = Aheader::from_imffields(from, imffields);
if message_time > 0 && !from.is_null() { if message_time > 0 && !from.is_null() {
if 0 != dc_apeerstate_load_by_addr( peerstate =
&mut peerstate, Peerstate::from_addr(context, &context.sql.clone().read().unwrap(), to_str(from));
&context.sql.clone().read().unwrap(),
from, if let Some(ref mut peerstate) = peerstate {
) {
if let Some(ref header) = autocryptheader { if let Some(ref header) = autocryptheader {
dc_apeerstate_apply_header(&mut peerstate, header, message_time); peerstate.apply_header(&header, message_time as u64);
dc_apeerstate_save_to_db( peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
&mut peerstate, } else if message_time as u64 > peerstate.last_seen_autocrypt
&context.sql.clone().read().unwrap(),
0i32,
);
} else if message_time > peerstate.last_seen_autocrypt
&& 0 == contains_report(in_out_message) && 0 == contains_report(in_out_message)
{ {
dc_apeerstate_degrade_encryption(&mut peerstate, message_time); peerstate.degrade_encryption(message_time as u64);
dc_apeerstate_save_to_db( peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
&peerstate,
&context.sql.clone().read().unwrap(),
0i32,
);
} }
} else if let Some(ref header) = autocryptheader { } else if let Some(ref header) = autocryptheader {
dc_apeerstate_init_from_header(&mut peerstate, header, message_time); let p = Peerstate::from_header(context, header, message_time as u64);
dc_apeerstate_save_to_db(&peerstate, &context.sql.clone().read().unwrap(), 1i32); p.save_to_db(&context.sql.clone().read().unwrap(), true);
peerstate = Some(p);
} }
} }
/* load private key for decryption */ /* load private key for decryption */
@@ -657,21 +647,23 @@ pub unsafe fn dc_e2ee_decrypt(
self_addr, self_addr,
&context.sql.clone().read().unwrap(), &context.sql.clone().read().unwrap(),
) { ) {
if peerstate.last_seen == 0 { if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
dc_apeerstate_load_by_addr( peerstate = Peerstate::from_addr(
&mut peerstate, &context,
&context.sql.clone().read().unwrap(), &context.sql.clone().read().unwrap(),
from, to_str(from),
); );
} }
if 0 != peerstate.degrade_event { if let Some(ref peerstate) = peerstate {
dc_handle_degrade_event(context, &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.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 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; (*helper).signatures = malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
dc_hash_init((*helper).signatures, 3i32, 1i32); dc_hash_init((*helper).signatures, 3i32, 1i32);
@@ -706,7 +698,6 @@ pub unsafe fn dc_e2ee_decrypt(
mailimf_fields_free(gossip_headers); mailimf_fields_free(gossip_headers);
} }
dc_apeerstate_unref(&mut peerstate);
free(from as *mut libc::c_void); free(from as *mut libc::c_void);
free(self_addr as *mut libc::c_void); free(self_addr as *mut libc::c_void);
} }
@@ -752,30 +743,25 @@ unsafe fn update_gossip_peerstates(
) )
.is_null() .is_null()
{ {
let mut peerstate = dc_apeerstate_new(context); let mut peerstate = Peerstate::from_addr(
if 0 == dc_apeerstate_load_by_addr( context,
&mut peerstate,
&context.sql.clone().read().unwrap(), &context.sql.clone().read().unwrap(),
CString::new(header.addr.clone()).unwrap().as_ptr(), &header.addr,
) { );
dc_apeerstate_init_from_gossip(&mut peerstate, header, message_time); if let Some(ref mut peerstate) = peerstate {
dc_apeerstate_save_to_db( peerstate.apply_gossip(header, message_time as u64);
&mut peerstate, peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
&context.sql.clone().read().unwrap(),
1i32,
);
} else { } else {
dc_apeerstate_apply_gossip(&mut peerstate, header, message_time); let p = Peerstate::from_gossip(context, header, message_time as u64);
dc_apeerstate_save_to_db( p.save_to_db(&context.sql.clone().read().unwrap(), true);
&mut peerstate, peerstate = Some(p);
&context.sql.clone().read().unwrap(),
0i32,
);
} }
if 0 != peerstate.degrade_event { if let Some(peerstate) = peerstate {
dc_handle_degrade_event(context, &peerstate); if peerstate.degrade_event.is_some() {
dc_handle_degrade_event(context, &peerstate);
}
} }
dc_apeerstate_unref(&mut peerstate);
if gossipped_addr.is_null() { if gossipped_addr.is_null() {
gossipped_addr = gossipped_addr =
malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t; malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;

View File

@@ -9,6 +9,7 @@ use crate::dc_log::*;
use crate::dc_loginparam::*; use crate::dc_loginparam::*;
use crate::dc_oauth2::dc_get_oauth2_access_token; use crate::dc_oauth2::dc_get_oauth2_access_token;
use crate::dc_sqlite3::*; use crate::dc_sqlite3::*;
use crate::dc_tools::{to_str, to_string};
use crate::types::*; use crate::types::*;
pub const DC_IMAP_SEEN: usize = 0x0001; 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. /// 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? // TODO: lots languages missing - maybe there is a list somewhere on other MUAs?
// however, if we fail to find out the sent-folder, // however, if we fail to find out the sent-folder,

View File

@@ -1,4 +1,3 @@
use crate::dc_apeerstate::*;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_contact::*; use crate::dc_contact::*;
use crate::dc_context::dc_context_t; use crate::dc_context::dc_context_t;
@@ -8,6 +7,7 @@ use crate::dc_lot::*;
use crate::dc_param::*; use crate::dc_param::*;
use crate::dc_strencode::*; use crate::dc_strencode::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*; use crate::types::*;
use crate::x::*; 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 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 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 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 qr_parsed: *mut dc_lot_t = dc_lot_new();
let mut chat_id: uint32_t = 0i32 as uint32_t; let mut chat_id: uint32_t = 0i32 as uint32_t;
let mut device_msg: *mut libc::c_char = 0 as *mut libc::c_char; 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 => {} 16562876845594826114 => {}
_ => { _ => {
if !fingerprint.is_null() { 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 addr.is_null() || invitenumber.is_null() || auth.is_null() {
if 0 != dc_apeerstate_load_by_fingerprint( if let Some(peerstate) = peerstate {
&mut peerstate,
&context.sql.clone().read().unwrap(),
fingerprint,
) {
(*qr_parsed).state = 210i32; (*qr_parsed).state = 210i32;
let c_addr = peerstate.addr.as_ref().map(to_cstring);
(*qr_parsed).id = dc_add_or_lookup_contact( (*qr_parsed).id = dc_add_or_lookup_contact(
context, context,
0 as *const libc::c_char, 0 as *const libc::c_char,
peerstate.addr, c_addr
.map(|a| a.as_ptr())
.unwrap_or_else(|| std::ptr::null()),
0x80i32, 0x80i32,
0 as *mut libc::c_int, 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(addr as *mut libc::c_void);
free(fingerprint 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(payload as *mut libc::c_void);
free(name as *mut libc::c_void); free(name as *mut libc::c_void);
free(invitenumber 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(device_msg as *mut libc::c_void);
free(grpname as *mut libc::c_void); free(grpname as *mut libc::c_void);
free(grpid as *mut libc::c_void); free(grpid as *mut libc::c_void);
return qr_parsed;
qr_parsed
} }

View File

@@ -7,7 +7,6 @@ use mmime::mmapstring::*;
use mmime::other::*; use mmime::other::*;
use crate::constants::*; use crate::constants::*;
use crate::dc_apeerstate::*;
use crate::dc_array::*; use crate::dc_array::*;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_contact::*; use crate::dc_contact::*;
@@ -27,6 +26,7 @@ use crate::dc_stock::*;
use crate::dc_strbuilder::*; use crate::dc_strbuilder::*;
use crate::dc_strencode::*; use crate::dc_strencode::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*; use crate::types::*;
use crate::x::*; use crate::x::*;
@@ -1847,10 +1847,9 @@ unsafe fn check_verified_properties(
to_ids: *const dc_array_t, to_ids: *const dc_array_t,
failure_reason: *mut *mut libc::c_char, failure_reason: *mut *mut libc::c_char,
) -> libc::c_int { ) -> libc::c_int {
let mut current_block: u64; let mut current_block: u64 = 0;
let mut everythings_okay: libc::c_int = 0i32; let mut everythings_okay: libc::c_int = 0i32;
let contact: *mut dc_contact_t = dc_contact_new(context); 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 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 q3: *mut libc::c_char = 0 as *mut libc::c_char;
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; 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 // this check is skipped for SELF as there is no proper SELF-peerstate
// and results in group-splits otherwise. // and results in group-splits otherwise.
if from_id != 1i32 as libc::c_uint { if from_id != 1i32 as libc::c_uint {
if 0 == dc_apeerstate_load_by_addr( let peerstate = Peerstate::from_addr(
&mut peerstate, context,
&context.sql.clone().read().unwrap(), &context.sql.clone().read().unwrap(),
(*contact).addr, to_str((*contact).addr),
) || dc_contact_is_verified_ex(contact, Some(&peerstate)) != 2i32 );
{
if peerstate.is_none() || dc_contact_is_verified_ex(contact, peerstate.as_ref()) != 2 {
*failure_reason = dc_mprintf( *failure_reason = dc_mprintf(
b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char, 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 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); dc_log_warning(context, 0i32, *failure_reason);
current_block = 14837890932895028253; current_block = 14837890932895028253;
} else if !dc_apeerstate_has_verified_key( } else if let Some(peerstate) = peerstate {
&peerstate, if !peerstate.has_verified_key((*(*mimeparser).e2ee_helper).signatures) {
(*(*mimeparser).e2ee_helper).signatures, *failure_reason = dc_mprintf(
) { b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char,
*failure_reason = dc_mprintf( b"The message was sent with non-verified encryption.\x00" as *const u8
b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char, 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;
dc_log_warning(context, 0i32, *failure_reason); }
current_block = 14837890932895028253;
} else { } else {
current_block = 15904375183555213903; current_block = 15904375183555213903;
} }
@@ -1920,27 +1919,26 @@ unsafe fn check_verified_properties(
let to_addr: *const libc::c_char = let to_addr: *const libc::c_char =
sqlite3_column_text(stmt, 0i32) as *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 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( if !dc_hash_find(
(*(*mimeparser).e2ee_helper).gossipped_addr, (*(*mimeparser).e2ee_helper).gossipped_addr,
to_addr as *const libc::c_void, to_addr as *const libc::c_void,
strlen(to_addr) as libc::c_int, strlen(to_addr) as libc::c_int,
) )
.is_null() .is_null()
&& 0 != dc_apeerstate_load_by_addr( && peerstate.is_some()
&mut peerstate,
&context.sql.clone().read().unwrap(),
to_addr,
)
{ {
let peerstate = peerstate.as_mut().unwrap();
if 0 == is_verified if 0 == is_verified
|| strcmp( || peerstate.verified_key_fingerprint
peerstate.verified_key_fingerprint, != peerstate.public_key_fingerprint
peerstate.public_key_fingerprint, && peerstate.verified_key_fingerprint
) != 0i32 != peerstate.gossip_key_fingerprint
&& strcmp(
peerstate.verified_key_fingerprint,
peerstate.gossip_key_fingerprint,
) != 0i32
{ {
dc_log_info( dc_log_info(
context, context,
@@ -1949,14 +1947,12 @@ unsafe fn check_verified_properties(
(*contact).addr, (*contact).addr,
to_addr, to_addr,
); );
let fp = peerstate.gossip_key_fingerprint; let fp = peerstate.gossip_key_fingerprint.clone();
dc_apeerstate_set_verified(&mut peerstate, 0i32, fp, 2i32); if let Some(fp) = fp {
dc_apeerstate_save_to_db( peerstate.set_verified(0, &fp, 2);
&mut peerstate, peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
&context.sql.clone().read().unwrap(), is_verified = 1i32;
0i32, }
);
is_verified = 1i32
} }
} }
if !(0 == is_verified) { if !(0 == is_verified) {
@@ -1985,11 +1981,11 @@ unsafe fn check_verified_properties(
} }
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
dc_contact_unref(contact); dc_contact_unref(contact);
dc_apeerstate_unref(&mut peerstate);
free(to_ids_str as *mut libc::c_void); free(to_ids_str as *mut libc::c_void);
sqlite3_free(q3 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) { 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 { if !(*better_msg).is_null() && carray_count((*mime_parser).parts) > 0i32 as libc::c_uint {
let mut part: *mut dc_mimepart_t = let mut part: *mut dc_mimepart_t =

View File

@@ -1,7 +1,7 @@
use mmime::mailimf_types::*; use mmime::mailimf_types::*;
use crate::constants::Event; use crate::constants::Event;
use crate::dc_apeerstate::*; use crate::dc_aheader::EncryptPreference;
use crate::dc_array::*; use crate::dc_array::*;
use crate::dc_chat::*; use crate::dc_chat::*;
use crate::dc_configure::*; use crate::dc_configure::*;
@@ -21,6 +21,7 @@ use crate::dc_stock::*;
use crate::dc_strencode::*; use crate::dc_strencode::*;
use crate::dc_token::*; use crate::dc_token::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*; use crate::types::*;
use crate::x::*; use crate::x::*;
@@ -353,27 +354,28 @@ unsafe fn fingerprint_equals_sender(
let mut fingerprint_equal: libc::c_int = 0i32; let mut fingerprint_equal: libc::c_int = 0i32;
let contacts: *mut dc_array_t = dc_get_chat_contacts(context, contact_chat_id); 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 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) { 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( if !(!dc_contact_load_from_db(
contact, contact,
&context.sql.clone().read().unwrap(), &context.sql.clone().read().unwrap(),
dc_array_get_id(contacts, 0i32 as size_t), dc_array_get_id(contacts, 0i32 as size_t),
) || 0 ) || peerstate.is_some())
== dc_apeerstate_load_by_addr(
&mut peerstate,
&context.sql.clone().read().unwrap(),
(*contact).addr,
))
{ {
fingerprint_normalized = dc_normalize_fingerprint_c(fingerprint); let peerstate = peerstate.as_ref().unwrap();
if strcasecmp(fingerprint_normalized, peerstate.public_key_fingerprint) == 0i32 { let fingerprint_normalized = dc_normalize_fingerprint(to_str(fingerprint));
fingerprint_equal = 1i32 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_contact_unref(contact);
dc_array_unref(contacts); dc_array_unref(contacts);
@@ -973,23 +975,20 @@ unsafe fn mark_peer_as_verified(
context: &dc_context_t, context: &dc_context_t,
fingerprint: *const libc::c_char, fingerprint: *const libc::c_char,
) -> libc::c_int { ) -> libc::c_int {
let mut success: libc::c_int = 0i32; let mut success = 0;
let mut peerstate = dc_apeerstate_new(context);
if !(0 if let Some(ref mut peerstate) = Peerstate::from_fingerprint(
== dc_apeerstate_load_by_fingerprint( context,
&mut peerstate, &context.sql.clone().read().unwrap(),
&context.sql.clone().read().unwrap(), to_str(fingerprint),
fingerprint, ) {
)) if peerstate.set_verified(1, to_str(fingerprint), 2) {
{ peerstate.prefer_encrypt = EncryptPreference::Mutual;
if !(0 == dc_apeerstate_set_verified(&mut peerstate, 1i32, fingerprint, 2i32)) { peerstate.to_save = Some(ToSave::All);
peerstate.prefer_encrypt = 1i32; peerstate.save_to_db(&context.sql.clone().read().unwrap(), false);
peerstate.to_save |= 0x2i32; success = 1;
dc_apeerstate_save_to_db(&mut peerstate, &context.sql.clone().read().unwrap(), 0i32);
success = 1i32
} }
} }
dc_apeerstate_unref(&mut peerstate);
success success
} }
@@ -1047,7 +1046,7 @@ unsafe fn encrypted_and_signed(
1 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 stmt;
let contact_id: uint32_t; let contact_id: uint32_t;
let mut contact_chat_id: uint32_t = 0i32 as 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 // 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 // with things they cannot fix, so the user is just kicked from the verified group
// (and he will know this and can fix this) // (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( stmt = dc_sqlite3_prepare(
context, context,
&context.sql.clone().read().unwrap(), &context.sql.clone().read().unwrap(),
b"SELECT id FROM contacts WHERE addr=?;\x00" as *const u8 as *const libc::c_char, 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); sqlite3_step(stmt);
contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t; contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t;
sqlite3_finalize(stmt); 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, &mut contact_chat_id,
0 as *mut libc::c_int, 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); dc_add_device_msg(context, contact_chat_id, msg);
free(msg as *mut libc::c_void); free(msg as *mut libc::c_void);
(context.cb)( (context.cb)(

View File

@@ -1,10 +1,10 @@
use crate::constants::*; use crate::constants::*;
use crate::dc_apeerstate::*;
use crate::dc_context::dc_context_t; use crate::dc_context::dc_context_t;
use crate::dc_hash::*; use crate::dc_hash::*;
use crate::dc_log::*; use crate::dc_log::*;
use crate::dc_param::*; use crate::dc_param::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::peerstate::*;
use crate::types::*; use crate::types::*;
use crate::x::*; use crate::x::*;
@@ -906,16 +906,14 @@ pub unsafe fn dc_sqlite3_open(
as *const libc::c_char, as *const libc::c_char,
); );
while sqlite3_step(stmt) == 100 { while sqlite3_step(stmt) == 100 {
let mut peerstate = dc_apeerstate_new(context); if let Some(ref mut peerstate) = Peerstate::from_addr(
if 0 != dc_apeerstate_load_by_addr( context,
&mut peerstate,
sql, sql,
sqlite3_column_text(stmt, 0) as *const libc::c_char, to_str(sqlite3_column_text(stmt, 0) as *const libc::c_char),
) && 0 != dc_apeerstate_recalc_fingerprint(&mut peerstate) ) {
{ peerstate.recalc_fingerprint();
dc_apeerstate_save_to_db(&mut peerstate, sql, 0); peerstate.save_to_db(sql, false);
} }
dc_apeerstate_unref(&mut peerstate);
} }
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
} }

View File

@@ -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() }
}

View File

@@ -22,9 +22,13 @@ extern crate smallvec;
#[macro_use] #[macro_use]
pub mod dc_log; 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_array;
pub mod dc_chat; pub mod dc_chat;
pub mod dc_chatlist; pub mod dc_chatlist;
@@ -64,8 +68,5 @@ pub mod dc_strbuilder;
pub mod dc_strencode; pub mod dc_strencode;
pub mod dc_token; pub mod dc_token;
pub mod dc_tools; pub mod dc_tools;
pub mod types;
pub mod x;
pub mod constants;
pub use self::constants::*; pub use self::constants::*;

564
src/peerstate.rs Normal file
View 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
}
}