mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 17:36:29 +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.
|
//! # [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()
|
||||||
|
|||||||
Reference in New Issue
Block a user