mirror of
https://github.com/chatmail/core.git
synced 2026-04-20 15:06:30 +03:00
commit6bc5d1b90eAuthor: holger krekel <holger@merlinux.eu> Date: Sun Jul 21 22:56:37 2019 +0200 fix fmt commit197d94ad9dMerge:7ce337c686678cAuthor: holger krekel <holger@merlinux.eu> Date: Sun Jul 21 22:51:16 2019 +0200 Merge remote-tracking branch 'origin/master' into eventlogging commit7ce337c6d0Author: holger krekel <holger@merlinux.eu> Date: Sun Jul 21 22:44:27 2019 +0200 left-over error logging commit10148d2e43Author: holger krekel <holger@merlinux.eu> Date: Sun Jul 21 22:03:17 2019 +0200 ignore non-utf8 parts of header fields (add comment why it shouldn't happen) don't throw error if no sql rows are returned commit69dc237ee3Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Sun Jul 21 12:56:04 2019 +0200 fix(receive_imf): remove recursive sql call commitdf5464ea80Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Sat Jul 20 17:05:24 2019 +0200 fix: blocked is an optional value commite4bf9956a5Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Sat Jul 20 16:50:56 2019 +0200 fix(msg): handle optional in_reply_to commitd353d9d9d8Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Sat Jul 20 16:17:25 2019 +0200 fix(chat): remove recursive sql usage commit1ad45ed4d6Author: holger krekel <holger@merlinux.eu> Date: Sat Jul 20 15:14:11 2019 +0200 fix rust fmt commit496e980a17Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Sat Jul 20 14:34:20 2019 +0200 use forked rusqlite commitfa09e46ed9Author: holger krekel <holger@merlinux.eu> Date: Sat Jul 20 12:37:51 2019 +0200 another pace where we might (and in my case did) get invalid utf8 commitd6de420b9aAuthor: holger krekel <holger@merlinux.eu> Date: Sat Jul 20 12:30:48 2019 +0200 fix some string issues, introduce to_string_lossy such that to_string() continues to panic on non-utf8 commit38eb708db8Author: holger krekel <holger@merlinux.eu> Date: Sat Jul 20 01:17:53 2019 +0200 for now make to_string() less strict as we often don't want to crash the whole app just because some non-proper utf8 came in (through a message we can't neccesarily congtrol) commit7a59da5f8fAuthor: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 22:48:39 2019 +0200 fix linting commitf13a1d4a2fAuthor: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 22:46:58 2019 +0200 fix some test flakyness commit7b3a450918Author: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 22:35:07 2019 +0200 - fix saved_mime test which broke to improper conversion of imf_raw_not_terminated - some cargo.toml updates no clue where they come from - log Message-ID for received messages commit169923b102Author: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 12:31:22 2019 +0200 formatting commit42688a0622Author: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 12:24:56 2019 +0200 remove some print statements commit35f3c0edd1Merge:e7a2362f58b1d6Author: holger krekel <holger@merlinux.eu> Date: Fri Jul 19 10:25:21 2019 +0200 Merge branch 'master' into eventlogging commite7a236264aAuthor: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 23:20:20 2019 +0200 print invalid strings commitaaa5b820d9Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 23:12:35 2019 +0200 cleanup commite7f0745010Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 23:03:57 2019 +0200 reduce direc usage of CString commitc68e7ae14eAuthor: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 22:47:47 2019 +0200 audit use of to_cstring and fix ub commit618087e5a7Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 21:38:52 2019 +0200 fix(imap): body ptr lifetime commit245abb8384Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 19:44:10 2019 +0200 remove debug commita3e1042001Author: dignifiedquire <dignifiedquire@users.noreply.github.com> Date: Thu Jul 18 18:30:54 2019 +0200 fix some things, add more debugging statements commit7b7ce9348fAuthor: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 15:11:57 2019 +0200 fix python lint issues commit7a4808ba0dAuthor: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 14:35:54 2019 +0200 cargofmt commit8f240f7153Author: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 14:03:57 2019 +0200 (dig,hpk) pull out job collection from sql query/lock logic commit7d0b5d8abbAuthor: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 12:52:02 2019 +0200 remove print statements and fix a crash commitee317cb1b5Author: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 11:38:10 2019 +0200 fix some merge issues commit7b736fe635Author: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 11:16:38 2019 +0200 (dig,hpk) add test and fix for wrong dbs commitc7db15352aMerge:0b371670c5015dAuthor: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 09:59:44 2019 +0200 Merge branch 'master' into eventlogging commit0b37167be8Author: holger krekel <holger@merlinux.eu> Date: Thu Jul 18 00:06:05 2019 +0200 address @dignifiedquire comments commit5cac4b5076Author: holger krekel <holger@merlinux.eu> Date: Wed Jul 17 12:47:22 2019 +0200 remove spurious print commit475a41beb3Author: holger krekel <holger@merlinux.eu> Date: Wed Jul 17 12:31:12 2019 +0200 address @dignifiedquire rustyness comment and fix changelog commitad4be80b4eAuthor: holger krekel <holger@merlinux.eu> Date: Wed Jul 17 10:25:25 2019 +0200 make smtp/imap connect() return bool instead of c-int commit8737c1d142Author: holger krekel <holger@merlinux.eu> Date: Wed Jul 17 09:26:33 2019 +0200 cleanup some parts, add comments commit964fe466ccAuthor: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 20:05:41 2019 +0200 wip-commit which passes all tests with proper finalization commit43936e7db7Author: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 16:17:42 2019 +0200 snapshot of my current debugging state commit0e80ce9c39Author: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 12:57:19 2019 +0200 more aggressively skip perform API when threads are closing commitc652bae68aAuthor: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 12:06:05 2019 +0200 intermediate wip commit commitbc904a495dAuthor: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 11:18:56 2019 +0200 add some logging, and a more precise teardown for online python tests commit8d99444c6aAuthor: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 00:22:12 2019 +0200 fix std commit9dab53e0afAuthor: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 00:20:54 2019 +0200 rustfmt commit360089ac74Author: holger krekel <holger@merlinux.eu> Date: Tue Jul 16 00:03:49 2019 +0200 remove some debugging commite892c5cf4dAuthor: holger krekel <holger@merlinux.eu> Date: Mon Jul 15 23:31:30 2019 +0200 fix test for events commit9ad4c9a6feAuthor: holger krekel <holger@merlinux.eu> Date: Mon Jul 15 22:51:57 2019 +0200 wip try test that we see INFO events from the core
538 lines
20 KiB
Rust
538 lines
20 KiB
Rust
use std::collections::HashSet;
|
|
use std::fmt;
|
|
|
|
use num_traits::FromPrimitive;
|
|
|
|
use crate::aheader::*;
|
|
use crate::constants::*;
|
|
use crate::context::Context;
|
|
use crate::dc_chat::*;
|
|
use crate::key::*;
|
|
use crate::sql::{self, Sql};
|
|
|
|
/// Peerstate represents the state of an Autocrypt peer.
|
|
pub struct Peerstate<'a> {
|
|
pub context: &'a Context,
|
|
pub addr: Option<String>,
|
|
pub last_seen: i64,
|
|
pub last_seen_autocrypt: i64,
|
|
pub prefer_encrypt: EncryptPreference,
|
|
pub public_key: Option<Key>,
|
|
pub public_key_fingerprint: Option<String>,
|
|
pub gossip_key: Option<Key>,
|
|
pub gossip_timestamp: i64,
|
|
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>,
|
|
}
|
|
|
|
impl<'a> PartialEq for Peerstate<'a> {
|
|
fn eq(&self, other: &Peerstate) -> bool {
|
|
self.addr == other.addr
|
|
&& self.last_seen == other.last_seen
|
|
&& self.last_seen_autocrypt == other.last_seen_autocrypt
|
|
&& self.prefer_encrypt == other.prefer_encrypt
|
|
&& self.public_key == other.public_key
|
|
&& self.public_key_fingerprint == other.public_key_fingerprint
|
|
&& self.gossip_key == other.gossip_key
|
|
&& self.gossip_timestamp == other.gossip_timestamp
|
|
&& self.gossip_key_fingerprint == other.gossip_key_fingerprint
|
|
&& self.verified_key == other.verified_key
|
|
&& self.verified_key_fingerprint == other.verified_key_fingerprint
|
|
&& self.to_save == other.to_save
|
|
&& self.degrade_event == other.degrade_event
|
|
}
|
|
}
|
|
|
|
impl<'a> Eq for Peerstate<'a> {}
|
|
|
|
impl<'a> fmt::Debug for Peerstate<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
f.debug_struct("Peerstate")
|
|
.field("addr", &self.addr)
|
|
.field("last_seen", &self.last_seen)
|
|
.field("last_seen_autocrypt", &self.last_seen_autocrypt)
|
|
.field("prefer_encrypt", &self.prefer_encrypt)
|
|
.field("public_key", &self.public_key)
|
|
.field("public_key_fingerprint", &self.public_key_fingerprint)
|
|
.field("gossip_key", &self.gossip_key)
|
|
.field("gossip_timestamp", &self.gossip_timestamp)
|
|
.field("gossip_key_fingerprint", &self.gossip_key_fingerprint)
|
|
.field("verified_key", &self.verified_key)
|
|
.field("verified_key_fingerprint", &self.verified_key_fingerprint)
|
|
.field("to_save", &self.to_save)
|
|
.field("degrade_event", &self.degrade_event)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[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, PartialEq, Eq)]
|
|
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 Context) -> 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 Context, header: &Aheader, message_time: i64) -> 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 Context, gossip_header: &Aheader, message_time: i64) -> 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 Context, _sql: &Sql, addr: &str) -> Option<Self> {
|
|
let query = "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;";
|
|
|
|
Self::from_stmt(context, query, &[addr])
|
|
}
|
|
|
|
pub fn from_fingerprint(context: &'a Context, _sql: &Sql, fingerprint: &str) -> Option<Self> {
|
|
let query = "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;";
|
|
|
|
let fp = fingerprint.as_bytes();
|
|
Self::from_stmt(context, query, params![fp, fp, fp])
|
|
}
|
|
|
|
fn from_stmt<P>(context: &'a Context, query: &str, params: P) -> Option<Self>
|
|
where
|
|
P: IntoIterator,
|
|
P::Item: rusqlite::ToSql,
|
|
{
|
|
context
|
|
.sql
|
|
.query_row(query, params, |row| {
|
|
let mut res = Self::new(context);
|
|
|
|
res.addr = Some(row.get(0)?);
|
|
res.last_seen = row.get(1)?;
|
|
res.last_seen_autocrypt = row.get(2)?;
|
|
res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default();
|
|
res.gossip_timestamp = row.get(5)?;
|
|
let pkf: String = row.get(7)?;
|
|
res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) };
|
|
let gkf: String = row.get(8)?;
|
|
res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) };
|
|
let vkf: String = row.get(10)?;
|
|
res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) };
|
|
|
|
res.public_key = row
|
|
.get(4)
|
|
.ok()
|
|
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
|
|
res.gossip_key = row
|
|
.get(6)
|
|
.ok()
|
|
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
|
|
let vk = row
|
|
.get(9)
|
|
.ok()
|
|
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
|
|
res.verified_key = if vk == res.gossip_key {
|
|
VerifiedKey::Gossip
|
|
} else if vk == res.public_key {
|
|
VerifiedKey::Public
|
|
} else {
|
|
VerifiedKey::None
|
|
};
|
|
|
|
Ok(res)
|
|
})
|
|
.ok()
|
|
}
|
|
|
|
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: i64) {
|
|
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: i64) {
|
|
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: i64) {
|
|
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: &Sql, create: bool) -> bool {
|
|
let mut success = false;
|
|
|
|
if self.addr.is_none() {
|
|
return success;
|
|
}
|
|
|
|
if create {
|
|
if sql::execute(
|
|
self.context,
|
|
sql,
|
|
"INSERT INTO acpeerstates (addr) VALUES(?);",
|
|
params![self.addr.as_ref().unwrap()],
|
|
)
|
|
.is_err()
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if self.to_save == Some(ToSave::All) || create {
|
|
success = sql::execute(
|
|
self.context,
|
|
sql,
|
|
"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=?;",
|
|
params![
|
|
self.last_seen,
|
|
self.last_seen_autocrypt,
|
|
self.prefer_encrypt as i64,
|
|
self.public_key.as_ref().map(|k| k.to_bytes()),
|
|
self.gossip_timestamp,
|
|
self.gossip_key.as_ref().map(|k| k.to_bytes()),
|
|
&self.public_key_fingerprint,
|
|
&self.gossip_key_fingerprint,
|
|
self.verified_key().map(|k| k.to_bytes()),
|
|
&self.verified_key_fingerprint,
|
|
&self.addr,
|
|
],
|
|
).is_ok();
|
|
} else if self.to_save == Some(ToSave::Timestamps) {
|
|
success = sql::execute(
|
|
self.context,
|
|
sql,
|
|
"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? \
|
|
WHERE addr=?;",
|
|
params![
|
|
self.last_seen,
|
|
self.last_seen_autocrypt,
|
|
self.gossip_timestamp,
|
|
&self.addr
|
|
],
|
|
)
|
|
.is_ok();
|
|
}
|
|
|
|
if self.to_save == Some(ToSave::All) || create {
|
|
dc_reset_gossiped_timestamp(self.context, 0);
|
|
}
|
|
|
|
success
|
|
}
|
|
|
|
pub fn has_verified_key(&self, fingerprints: &HashSet<String>) -> bool {
|
|
if self.verified_key.is_some() && self.verified_key_fingerprint.is_some() {
|
|
let vkc = self.verified_key_fingerprint.as_ref().unwrap();
|
|
if fingerprints.contains(vkc) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
false
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
use std::ffi::CStr;
|
|
use tempfile::{tempdir, TempDir};
|
|
|
|
use crate::context::*;
|
|
use crate::dc_tools::to_cstring;
|
|
use crate::x::free;
|
|
|
|
#[test]
|
|
fn test_peerstate_save_to_db() {
|
|
let ctx = unsafe { create_test_context() };
|
|
let addr = "hello@mail.com";
|
|
|
|
let pub_key = crate::key::Key::from_base64("xsBNBFztUVkBCADYaQl/UOUpRPd32nLRzx8eU0eI+jQEnG+g5anjYA+3oct1rROGl5SygjMULDKdaUy27O3o9Srsti0YjA7uxZnavIqhSopJhFidqY1M1wA9JZa/duucZdNwUGbjGIRsS/4Cjr5+3svscK24hVYub1dvDWXpwUTnj3K6xOEnJdoM+MhCqtSD5+zcJhFc9vyZm9ZTGWUxAhKh0iJTcCD8V6CQ3XZ2z9GruwzZT/FTFovWrz7m3TUI2OdSSHh0eZLRGEoxMCT/vzflAFGAr8ijCaRsEIfqP6FW8uQWnFTqkjxEUCZG6XkeFHB84aj5jqYG/1KCLjL5vEKwfl1tz/WnPhY7ABEBAAHNEDxoZWxsb0BtYWlsLmNvbT7CwIkEEAEIADMCGQEFAlztUVoCGwMECwkIBwYVCAkKCwIDFgIBFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7ijAwf+PTsuawUax9cNPn1bN90H+g9qyHZJMEwKXtUnNaXJxPW3iB7ThhpCiCzsZwP7+l7ArS8tmLeNDw2bENtcf1XCv4wovP2fdXOP3QOUUFX/GdakcTwv7DzC7CO0grB1HtaPhGw/6UX2o2cx2i9xiUf4Givq2MfCbgAW5zloH6WXGPb6yLQYJXxqDIphr4+uZDb+bMAyWHN/DUkAjHrV8nnVki7PMHqzzZpwglalxMX8RGeiGZE39ALJKL/Og87DMFah87/yoxQWGoS7Wqv0XDcCPKoTCPrpk8pOe2KEsq/lz215nefHd4aRpfUX5YCYa8HPvvfPQbGF73uvyQw5w7qjis7ATQRc7VFZAQgAt8ONdnX6KEEQ5Jw6ilJ+LBtY44SP5t0I3eK+goKepgIiKhjGDa+Mntyi4jdhH+HO6kvK5SHMh2sPp4rRO/WKHJwWFySyM1OdyiywhyH0J9R5rBY4vPHsJjf6vSKJdWLWT+ho1fNet2IIC+jVCYli91MAMbRvk6EKVj1nCc+67giOahXEkHt6xxkeCGlOvbw8hxGj1A8+AC1BLms/OR3oc4JMi9O3kq6uG0z9tlUEerac9HVwcjoO1XLe+hJhoT5H+TbnGjPuhuURP3pFiIKHpbRYgUfdSAY0dTObO7t4I5y/drPOrCTnWrBUg2wXAECUhpRKow9/ai2YemLv9KqhhwARAQABwsB2BBgBCAAgBQJc7VFaAhsMFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7jmyggAhs4QzCzIbT2OsAReBxkxtm0AI+g1HZ1KFKof5NDHfgv9C/Qu1I8mKEjlZzA4qFyPmLqntgwJ0RuFy6gLbljZBNCFO7vB478AhYtnWjuKZmA40HUPwcB1hEJ31c42akzfUbioY1TLLepngdsJg7Cm8O+rhI9+1WRA66haJDgFs793SVUDyJh8f9NX50l5zR87/bsV30CFSw0q4OSSy9VI/z+2g5khn1LnuuOrCfFnYIPYtJED1BfkXkosxGlgbzy79VvGmI9d23x4atDK7oBPCzIj+lP8sytJ0u3HOguXi9OgDitKy+Pt1r8gH8frdktMJr5Ts6DW+tIn2vR23KR8aA==", KeyType::Public).unwrap();
|
|
|
|
let mut peerstate = Peerstate {
|
|
context: &ctx.ctx,
|
|
addr: Some(addr.into()),
|
|
last_seen: 10,
|
|
last_seen_autocrypt: 11,
|
|
prefer_encrypt: EncryptPreference::Mutual,
|
|
public_key: Some(pub_key.clone()),
|
|
public_key_fingerprint: Some(pub_key.fingerprint()),
|
|
gossip_key: Some(pub_key.clone()),
|
|
gossip_timestamp: 12,
|
|
gossip_key_fingerprint: Some(pub_key.fingerprint()),
|
|
verified_key: VerifiedKey::Gossip,
|
|
verified_key_fingerprint: Some(pub_key.fingerprint()),
|
|
to_save: Some(ToSave::All),
|
|
degrade_event: None,
|
|
};
|
|
|
|
assert!(peerstate.save_to_db(&ctx.ctx.sql, true), "failed to save");
|
|
|
|
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into())
|
|
.expect("failed to load peerstate from db");
|
|
|
|
// clear to_save, as that is not persissted
|
|
peerstate.to_save = None;
|
|
assert_eq!(peerstate, peerstate_new);
|
|
}
|
|
|
|
// TODO: don't copy this from stress.rs
|
|
#[allow(dead_code)]
|
|
struct TestContext {
|
|
ctx: Context,
|
|
dir: TempDir,
|
|
}
|
|
|
|
unsafe extern "C" fn cb(
|
|
_context: &Context,
|
|
_event: Event,
|
|
_data1: libc::uintptr_t,
|
|
_data2: libc::uintptr_t,
|
|
) -> libc::uintptr_t {
|
|
0
|
|
}
|
|
|
|
unsafe fn create_test_context() -> TestContext {
|
|
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
|
|
let dir = tempdir().unwrap();
|
|
let dbfile = to_cstring(dir.path().join("db.sqlite").to_str().unwrap());
|
|
assert_eq!(
|
|
dc_open(&mut ctx, dbfile, std::ptr::null()),
|
|
1,
|
|
"Failed to open {}",
|
|
CStr::from_ptr(dbfile as *const _).to_str().unwrap()
|
|
);
|
|
|
|
free(dbfile as *mut _);
|
|
|
|
TestContext { ctx: ctx, dir: dir }
|
|
}
|
|
}
|