wot-network 0.0.6

Data structures for OpenPGP Web of Trust calculations
Documentation
#[cfg(doc)]
use crate::Network;
use crate::{Binding, Certificate, Identity, Regex, TrustDepth};

/// An edge in the WoT network (either a [Certification] or a [Delegation])
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub enum Edge {
    Certification(Certification),
    Delegation(Delegation),
}

impl Edge {
    pub fn issuer(&self) -> &Certificate {
        match self {
            Self::Certification(certification) => certification.issuer(),
            Self::Delegation(delegation) => delegation.issuer(),
        }
    }

    pub fn target(&self) -> &Certificate {
        match self {
            Self::Certification(certification) => certification.target_cert(),
            Self::Delegation(delegation) => delegation.target(),
        }
    }

    pub fn is_delegation(&self) -> bool {
        matches!(self, Edge::Delegation(..))
    }

    pub fn trust_amount(&self) -> u8 {
        match self {
            Self::Certification(_) => 120,
            Self::Delegation(delegation) => delegation.trust_amount,
        }
    }

    pub fn trust_depth(&self) -> TrustDepth {
        match self {
            Self::Certification(_) => TrustDepth::None,
            Self::Delegation(delegation) => delegation.trust_depth,
        }
    }
}

/// A type of [Edge] that represents a certification over a [`Binding`].
///
/// `Certification`s can only be created by using [`Network::add_binding`].
///
/// ```
/// use wot_network::Network;
///
/// let mut network = Network::new();
/// network.add_binding(
///     "issuer_cert_id".into(),
///     "target_cert_id".into(),
///     "target@user_id.com".into(),
///     120,
/// );
/// ```
// TODO: There's currently no way to programatically create a Certification outside of add_binding.
//       I assume there should be another way?
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub struct Certification {
    pub issuer: Certificate,
    pub target: Binding, // FIXME: drop? - redundant with network hashmap key
}

impl Certification {
    pub fn issuer(&self) -> &Certificate {
        &self.issuer
    }

    pub fn target_cert(&self) -> &Certificate {
        &self.target.cert
    }
    pub fn target_id(&self) -> &Identity {
        &self.target.identity
    }
}

/// A type of [Edge] that represents a delegation to a second certificate
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub struct Delegation {
    pub issuer: Certificate,
    pub target: Certificate, // FIXME: drop? - redundant with network hashmap key
    pub trust_amount: u8,
    pub trust_depth: TrustDepth,
    /// If any regex exists in a delegation, then at least one of the regexes must match the
    /// target User ID for a delegation edge to be usable in a path.
    pub regexes: Vec<Regex>,
}

impl Delegation {
    pub fn new(
        issuer: Certificate,
        target: Certificate,
        trust_amount: u8,
        trust_depth: TrustDepth,
        regexes: Vec<Regex>,
    ) -> Self {
        Delegation {
            issuer,
            target,
            trust_amount,
            trust_depth,
            regexes,
        }
    }

    pub fn issuer(&self) -> &Certificate {
        &self.issuer
    }

    pub fn target(&self) -> &Certificate {
        &self.target
    }

    pub fn trust_amount(&self) -> u8 {
        self.trust_amount
    }

    pub fn trust_depth(&self) -> TrustDepth {
        self.trust_depth
    }

    fn regexes(&self) -> &[Regex] {
        &self.regexes
    }

    pub fn regex_match(&self, target_user_id: &Identity) -> bool {
        if self.regexes().is_empty() {
            return true;
        }

        self.regexes()
            .iter()
            .any(|regex| regex.matches(target_user_id))
    }
}