mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 05:22:14 +03:00
Add missing documentation to peerstate.rs
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
//! # [Autocrypt Peer State](https://autocrypt.org/level1.html#peer-state-management) module.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use anyhow::{Context as _, Error, Result};
|
||||
@@ -20,40 +18,81 @@ use crate::mimeparser::SystemMessage;
|
||||
use crate::sql::Sql;
|
||||
use crate::stock_str;
|
||||
|
||||
/// Type of the public key stored inside the peerstate.
|
||||
#[derive(Debug)]
|
||||
pub enum PeerstateKeyType {
|
||||
/// Pubilc key sent in the `Autocrypt-Gossip` header.
|
||||
GossipKey,
|
||||
|
||||
/// Public key sent in the `Autocrypt` header.
|
||||
PublicKey,
|
||||
}
|
||||
|
||||
/// Verification status of the contact peerstate.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum PeerstateVerifiedStatus {
|
||||
/// Peerstate is not verified.
|
||||
Unverified = 0,
|
||||
//Verified = 1, // not used
|
||||
/// Peerstate is verified and we assume that the contact has verified our peerstate.
|
||||
BidirectVerified = 2,
|
||||
}
|
||||
|
||||
/// Peerstate represents the state of an Autocrypt peer.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Peerstate {
|
||||
/// E-mail address of the contact.
|
||||
pub addr: String,
|
||||
|
||||
/// Timestamp of the latest peerstate update.
|
||||
///
|
||||
/// Updated when a message is received from a contact,
|
||||
/// either with or without `Autocrypt` header.
|
||||
pub last_seen: i64,
|
||||
|
||||
/// Timestamp of the latest `Autocrypt` header reception.
|
||||
pub last_seen_autocrypt: i64,
|
||||
|
||||
/// Encryption preference of the contact.
|
||||
pub prefer_encrypt: EncryptPreference,
|
||||
|
||||
/// Public key of the contact received in `Autocrypt` header.
|
||||
pub public_key: Option<SignedPublicKey>,
|
||||
|
||||
/// Fingerprint of the contact public key.
|
||||
pub public_key_fingerprint: Option<Fingerprint>,
|
||||
|
||||
/// Public key of the contact received in `Autocrypt-Gossip` header.
|
||||
pub gossip_key: Option<SignedPublicKey>,
|
||||
|
||||
/// Timestamp of the latest `Autocrypt-Gossip` header reception.
|
||||
///
|
||||
/// It is stored to avoid applying outdated gossiped key
|
||||
/// from delayed or reordered messages.
|
||||
pub gossip_timestamp: i64,
|
||||
|
||||
/// Fingerprint of the contact gossip key.
|
||||
pub gossip_key_fingerprint: Option<Fingerprint>,
|
||||
|
||||
/// Public key of the contact at the time it was verified,
|
||||
/// either directly or via gossip from the verified contact.
|
||||
pub verified_key: Option<SignedPublicKey>,
|
||||
|
||||
/// Fingerprint of the verified public key.
|
||||
pub verified_key_fingerprint: Option<Fingerprint>,
|
||||
|
||||
/// True if it was detected
|
||||
/// that the fingerprint of the key used in chats with
|
||||
/// opportunistic encryption was changed after Peerstate creation.
|
||||
pub fingerprint_changed: bool,
|
||||
|
||||
/// The address that verified this contact
|
||||
pub verifier: Option<String>,
|
||||
}
|
||||
|
||||
impl Peerstate {
|
||||
/// Creates a peerstate from the `Autocrypt` header.
|
||||
pub fn from_header(header: &Aheader, message_time: i64) -> Self {
|
||||
Peerstate {
|
||||
addr: header.addr.clone(),
|
||||
@@ -72,7 +111,7 @@ impl Peerstate {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create peerstate from gossip
|
||||
/// Create a peerstate from the `Autocrypt-Gossip` header.
|
||||
pub fn from_gossip(gossip_header: &Aheader, message_time: i64) -> Self {
|
||||
Peerstate {
|
||||
addr: gossip_header.addr.clone(),
|
||||
@@ -98,6 +137,7 @@ impl Peerstate {
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads peerstate corresponding to the given address from the database.
|
||||
pub async fn from_addr(context: &Context, addr: &str) -> Result<Option<Peerstate>> {
|
||||
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, \
|
||||
gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
|
||||
@@ -107,6 +147,7 @@ impl Peerstate {
|
||||
Self::from_stmt(context, query, paramsv![addr]).await
|
||||
}
|
||||
|
||||
/// Loads peerstate corresponding to the given fingerprint from the database.
|
||||
pub async fn from_fingerprint(
|
||||
context: &Context,
|
||||
fingerprint: &Fingerprint,
|
||||
@@ -122,6 +163,10 @@ impl Peerstate {
|
||||
Self::from_stmt(context, query, paramsv![fp, fp, fp]).await
|
||||
}
|
||||
|
||||
/// Loads peerstate by address or verified fingerprint.
|
||||
///
|
||||
/// If the address is different but verified fingerprint is the same,
|
||||
/// peerstate with corresponding verified fingerprint is preferred.
|
||||
pub async fn from_verified_fingerprint_or_addr(
|
||||
context: &Context,
|
||||
fingerprint: &Fingerprint,
|
||||
@@ -231,11 +276,15 @@ impl Peerstate {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset Autocrypt peerstate.
|
||||
///
|
||||
/// Used when it is detected that the contact no longer uses Autocrypt.
|
||||
pub fn degrade_encryption(&mut self, message_time: i64) {
|
||||
self.prefer_encrypt = EncryptPreference::Reset;
|
||||
self.last_seen = message_time;
|
||||
}
|
||||
|
||||
/// Updates peerstate according to the given `Autocrypt` header.
|
||||
pub fn apply_header(&mut self, header: &Aheader, message_time: i64) {
|
||||
if !addr_cmp(&self.addr, &header.addr) {
|
||||
return;
|
||||
@@ -258,6 +307,7 @@ impl Peerstate {
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates peerstate according to the given `Autocrypt-Gossip` header.
|
||||
pub fn apply_gossip(&mut self, gossip_header: &Aheader, message_time: i64) {
|
||||
if self.addr.to_lowercase() != gossip_header.addr.to_lowercase() {
|
||||
return;
|
||||
@@ -290,6 +340,7 @@ impl Peerstate {
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the contents of the `Autocrypt-Gossip` header for outgoing messages.
|
||||
pub fn render_gossip_header(&self, min_verified: PeerstateVerifiedStatus) -> Option<String> {
|
||||
if let Some(key) = self.peek_key(min_verified) {
|
||||
let header = Aheader::new(
|
||||
@@ -311,6 +362,9 @@ impl Peerstate {
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the peerstate into the contact public key.
|
||||
///
|
||||
/// Similar to [`Self::peek_key`], but consumes the peerstate and returns owned key.
|
||||
pub fn take_key(mut self, min_verified: PeerstateVerifiedStatus) -> Option<SignedPublicKey> {
|
||||
match min_verified {
|
||||
PeerstateVerifiedStatus::BidirectVerified => self.verified_key.take(),
|
||||
@@ -320,6 +374,15 @@ impl Peerstate {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the contact public key.
|
||||
///
|
||||
/// `min_verified` determines the minimum required verification status of the key.
|
||||
/// If verified key is requested, returns the verified key,
|
||||
/// otherwise returns the Autocrypt key.
|
||||
///
|
||||
/// Returned key is suitable for sending in `Autocrypt-Gossip` header.
|
||||
///
|
||||
/// Returns `None` if there is no suitable public key.
|
||||
pub fn peek_key(&self, min_verified: PeerstateVerifiedStatus) -> Option<&SignedPublicKey> {
|
||||
match min_verified {
|
||||
PeerstateVerifiedStatus::BidirectVerified => self.verified_key.as_ref(),
|
||||
@@ -380,6 +443,7 @@ impl Peerstate {
|
||||
}
|
||||
}
|
||||
|
||||
/// Saves the peerstate to the database.
|
||||
pub async fn save_to_db(&self, sql: &Sql) -> Result<()> {
|
||||
sql.execute(
|
||||
"INSERT INTO acpeerstates (
|
||||
@@ -428,6 +492,7 @@ impl Peerstate {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns true if verified key is contained in the given set of fingerprints.
|
||||
pub fn has_verified_key(&self, fingerprints: &HashSet<Fingerprint>) -> bool {
|
||||
if let Some(vkc) = &self.verified_key_fingerprint {
|
||||
fingerprints.contains(vkc) && self.verified_key.is_some()
|
||||
|
||||
Reference in New Issue
Block a user