wot_network/
network.rs

1use std::collections::HashMap;
2
3use crate::{Binding, Certificate, Certification, Delegation, Regex, TrustDepth};
4
5/// A "Web of Trust" network consisting of [Certification]s and [Delegation]s.
6///
7/// A [Network] represents a snapshot of valid nodes and edges in a set of OpenPGP Certificates
8/// at a reference time.
9///
10/// **NOTE**:
11///
12/// Users of this crate will usually want to create a `wot-network` graph from OpenPGP certificates.
13/// This involves applying all relevant OpenPGP semantics and forming a network of exactly
14/// those nodes and edges that are valid and active at the reference time.
15///
16/// One implementation of formation of `wot-network` graphs is available in
17/// [wot-network-rpgpie](https://crates.io/crates/wot-network-rpgpie).
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19#[derive(Debug, PartialEq, Clone)]
20pub struct Network {
21    // Certifications towards a binding
22    //
23    // In contrast to conventional trust graphs, the certification edges in this network are
24    // backwards, i.e. certifications pointing on binding.
25    pub certifications: HashMap<Binding, Vec<Certification>>,
26
27    // Delegations towards a cert.
28    //
29    // In contrast to conventional trust graphs, the delegation edges in this network are
30    // backwards, i.e. delegations pointing on a certification.
31    pub delegations: HashMap<Certificate, Vec<Delegation>>,
32}
33
34impl Default for Network {
35    fn default() -> Self {
36        Self::new()
37    }
38}
39
40impl Network {
41    pub fn new() -> Self {
42        Self {
43            certifications: Default::default(),
44            delegations: Default::default(),
45        }
46    }
47
48    pub fn num_edges(&self) -> usize {
49        self.certifications.len() + self.delegations.len()
50    }
51
52    pub fn add_binding(&mut self, issuer: Certificate, target: Binding) {
53        // FIXME: less cloning!?
54
55        let edge = Certification {
56            issuer: issuer.clone(),
57            target: target.clone(),
58        };
59
60        if let Some(edges) = self.certifications.get_mut(&Binding {
61            cert: target.cert.clone(),
62            identity: target.identity.clone(),
63        }) {
64            // add edge to pre-existing EdgeSet
65            edges.push(edge);
66        } else {
67            // make a new EdgeSet, put this edge in
68            let list = vec![edge];
69
70            self.certifications.insert(
71                Binding {
72                    cert: target.cert,
73                    identity: target.identity,
74                },
75                list,
76            );
77        }
78    }
79
80    pub fn add_delegation(
81        &mut self,
82        issuer: Certificate,
83        target_cert: Certificate,
84        trust_amount: u8,
85        trust_depth: TrustDepth,
86        regexes: Vec<Regex>,
87    ) {
88        // FIXME: less Certificate cloning!?
89
90        let edge = Delegation {
91            issuer: issuer.clone(),
92            target: target_cert.clone(),
93            trust_amount,
94            trust_depth,
95            regexes,
96        };
97
98        if let Some(edges) = self.delegations.get_mut(&target_cert) {
99            // Add edge to pre-existing EdgeSet
100            edges.push(edge);
101        } else {
102            // Make a new EdgeSet
103            let list = vec![edge];
104
105            // Add this EdgeSet to the Network
106            self.delegations.insert(target_cert, list);
107        }
108    }
109}
110
111/// A minimalistic representation of a network
112///
113/// This is effectively a [`Network`], but as a single combined vector instead of a HashMap over
114/// vectors. This is used to allow specification of test networks in a format that's easier to read
115/// for humans.
116#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
117#[derive(Debug, Clone)]
118pub struct MinimalNetwork {
119    pub certifications: Vec<Certification>,
120    pub delegations: Vec<Delegation>,
121}
122
123impl From<Network> for MinimalNetwork {
124    fn from(network: Network) -> Self {
125        let certifications = network.certifications.into_values().flatten().collect();
126        let delegations = network.delegations.into_values().flatten().collect();
127        MinimalNetwork {
128            certifications,
129            delegations,
130        }
131    }
132}
133
134impl From<MinimalNetwork> for Network {
135    fn from(minimal_network: MinimalNetwork) -> Self {
136        let mut certifications: HashMap<Binding, Vec<Certification>> = HashMap::new();
137        for cert in minimal_network.certifications {
138            certifications
139                .entry(cert.target.clone())
140                .or_default()
141                .push(cert);
142        }
143
144        let mut delegations: HashMap<Certificate, Vec<Delegation>> = HashMap::new();
145        for delegation in minimal_network.delegations {
146            delegations
147                .entry(delegation.target.clone())
148                .or_default()
149                .push(delegation);
150        }
151
152        Network {
153            certifications,
154            delegations,
155        }
156    }
157}