Add missing documentation to peerstate.rs

This commit is contained in:
link2xt
2023-01-23 14:50:47 +00:00
parent 37f20c6889
commit 800125c7a9

View File

@@ -1,7 +1,5 @@
//! # [Autocrypt Peer State](https://autocrypt.org/level1.html#peer-state-management) module. //! # [Autocrypt Peer State](https://autocrypt.org/level1.html#peer-state-management) module.
#![allow(missing_docs)]
use std::collections::HashSet; use std::collections::HashSet;
use anyhow::{Context as _, Error, Result}; use anyhow::{Context as _, Error, Result};
@@ -20,40 +18,81 @@ use crate::mimeparser::SystemMessage;
use crate::sql::Sql; use crate::sql::Sql;
use crate::stock_str; use crate::stock_str;
/// Type of the public key stored inside the peerstate.
#[derive(Debug)] #[derive(Debug)]
pub enum PeerstateKeyType { pub enum PeerstateKeyType {
/// Pubilc key sent in the `Autocrypt-Gossip` header.
GossipKey, GossipKey,
/// Public key sent in the `Autocrypt` header.
PublicKey, PublicKey,
} }
/// Verification status of the contact peerstate.
#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)] #[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)]
#[repr(u8)] #[repr(u8)]
pub enum PeerstateVerifiedStatus { pub enum PeerstateVerifiedStatus {
/// Peerstate is not verified.
Unverified = 0, Unverified = 0,
//Verified = 1, // not used //Verified = 1, // not used
/// Peerstate is verified and we assume that the contact has verified our peerstate.
BidirectVerified = 2, BidirectVerified = 2,
} }
/// Peerstate represents the state of an Autocrypt peer. /// Peerstate represents the state of an Autocrypt peer.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct Peerstate { pub struct Peerstate {
/// E-mail address of the contact.
pub addr: String, 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, pub last_seen: i64,
/// Timestamp of the latest `Autocrypt` header reception.
pub last_seen_autocrypt: i64, pub last_seen_autocrypt: i64,
/// Encryption preference of the contact.
pub prefer_encrypt: EncryptPreference, pub prefer_encrypt: EncryptPreference,
/// Public key of the contact received in `Autocrypt` header.
pub public_key: Option<SignedPublicKey>, pub public_key: Option<SignedPublicKey>,
/// Fingerprint of the contact public key.
pub public_key_fingerprint: Option<Fingerprint>, pub public_key_fingerprint: Option<Fingerprint>,
/// Public key of the contact received in `Autocrypt-Gossip` header.
pub gossip_key: Option<SignedPublicKey>, 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, pub gossip_timestamp: i64,
/// Fingerprint of the contact gossip key.
pub gossip_key_fingerprint: Option<Fingerprint>, 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>, pub verified_key: Option<SignedPublicKey>,
/// Fingerprint of the verified public key.
pub verified_key_fingerprint: Option<Fingerprint>, 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, pub fingerprint_changed: bool,
/// The address that verified this contact /// The address that verified this contact
pub verifier: Option<String>, pub verifier: Option<String>,
} }
impl Peerstate { impl Peerstate {
/// Creates a peerstate from the `Autocrypt` header.
pub fn from_header(header: &Aheader, message_time: i64) -> Self { pub fn from_header(header: &Aheader, message_time: i64) -> Self {
Peerstate { Peerstate {
addr: header.addr.clone(), 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 { pub fn from_gossip(gossip_header: &Aheader, message_time: i64) -> Self {
Peerstate { Peerstate {
addr: gossip_header.addr.clone(), 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>> { 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, \ let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, \
gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \ gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
@@ -107,6 +147,7 @@ impl Peerstate {
Self::from_stmt(context, query, paramsv![addr]).await Self::from_stmt(context, query, paramsv![addr]).await
} }
/// Loads peerstate corresponding to the given fingerprint from the database.
pub async fn from_fingerprint( pub async fn from_fingerprint(
context: &Context, context: &Context,
fingerprint: &Fingerprint, fingerprint: &Fingerprint,
@@ -122,6 +163,10 @@ impl Peerstate {
Self::from_stmt(context, query, paramsv![fp, fp, fp]).await 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( pub async fn from_verified_fingerprint_or_addr(
context: &Context, context: &Context,
fingerprint: &Fingerprint, 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) { pub fn degrade_encryption(&mut self, message_time: i64) {
self.prefer_encrypt = EncryptPreference::Reset; self.prefer_encrypt = EncryptPreference::Reset;
self.last_seen = message_time; self.last_seen = message_time;
} }
/// Updates peerstate according to the given `Autocrypt` header.
pub fn apply_header(&mut self, header: &Aheader, message_time: i64) { pub fn apply_header(&mut self, header: &Aheader, message_time: i64) {
if !addr_cmp(&self.addr, &header.addr) { if !addr_cmp(&self.addr, &header.addr) {
return; 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) { pub fn apply_gossip(&mut self, gossip_header: &Aheader, message_time: i64) {
if self.addr.to_lowercase() != gossip_header.addr.to_lowercase() { if self.addr.to_lowercase() != gossip_header.addr.to_lowercase() {
return; 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> { pub fn render_gossip_header(&self, min_verified: PeerstateVerifiedStatus) -> Option<String> {
if let Some(key) = self.peek_key(min_verified) { if let Some(key) = self.peek_key(min_verified) {
let header = Aheader::new( 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> { pub fn take_key(mut self, min_verified: PeerstateVerifiedStatus) -> Option<SignedPublicKey> {
match min_verified { match min_verified {
PeerstateVerifiedStatus::BidirectVerified => self.verified_key.take(), 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> { pub fn peek_key(&self, min_verified: PeerstateVerifiedStatus) -> Option<&SignedPublicKey> {
match min_verified { match min_verified {
PeerstateVerifiedStatus::BidirectVerified => self.verified_key.as_ref(), 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<()> { pub async fn save_to_db(&self, sql: &Sql) -> Result<()> {
sql.execute( sql.execute(
"INSERT INTO acpeerstates ( "INSERT INTO acpeerstates (
@@ -428,6 +492,7 @@ impl Peerstate {
Ok(()) Ok(())
} }
/// Returns true if verified key is contained in the given set of fingerprints.
pub fn has_verified_key(&self, fingerprints: &HashSet<Fingerprint>) -> bool { pub fn has_verified_key(&self, fingerprints: &HashSet<Fingerprint>) -> bool {
if let Some(vkc) = &self.verified_key_fingerprint { if let Some(vkc) = &self.verified_key_fingerprint {
fingerprints.contains(vkc) && self.verified_key.is_some() fingerprints.contains(vkc) && self.verified_key.is_some()