wot_network/lib.rs
1//! Data structures for OpenPGP Web of Trust calculations.
2//!
3//! These data structures model the bare minimum level of detail for Web of Trust calculations.
4//!
5//! See <https://codeberg.org/openpgp/wot/> for more context.
6//!
7//! A [Network] (the top level WoT object) models a set of [Certification] and [Delegation] edges,
8//! which represent relationships between [Certificate] and [Identity] objects.
9//!
10//! The goal of the representation in this crate is to model an absolutely minimal view of a WoT
11//! network. This minimalism keeps the task of correctly *forming* a WoT [Network] graph cleanly
12//! separated from the WoT algorithm that performs searches in the graph:
13//!
14//! All OpenPGP semantics considerations (such as validity, e.g. regarding expiration and
15//! revocation) are normalized out of the `wot-network` representation.
16//! Invalid objects (Certificates, Identities or Certifications) are simply not rendered in a
17//! [Network] view.
18//!
19//! It is the task of a separate "network formation" subsystem to interpret the semantics of
20//! OpenPGP certificates and transform them into a normalized [Network] graph.
21//!
22//! In particular, there is no notion of the passage of time in this WoT [Network] graph
23//! representation. A [Network] represents a snapshot of the Web of Trust relations within a set
24//! of Certificates at a given reference time.
25//!
26//! Searches in a Network are modeled with the [search::WotSearchTrait] and
27//! [search::ResidualNetworkTrait] traits.
28
29mod edge;
30pub(crate) mod id;
31mod network;
32pub mod search;
33mod trust_depth;
34pub mod util;
35
36use std::fmt;
37
38pub use edge::{Certification, Delegation, Edge};
39pub use id::{Certificate, Identity};
40pub use network::{MinimalNetwork, Network};
41pub use trust_depth::TrustDepth;
42
43/// A relationship between a [Certificate] and an [Identity]
44// TODO: The term binding in OpenPGP is very ambiguous.
45// A certificate may hold multiple bindings, so maybe `IdentityBinding` is more fitting?
46#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
47#[derive(Debug, Eq, Hash, PartialEq, Clone)]
48pub struct Binding {
49 pub cert: Certificate,
50 pub identity: Identity,
51}
52
53/// A regular expression that can be used to limit the applicability of [Delegation]s
54///
55/// See <https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.22> for the regex syntax that
56/// applies and what it applies to.
57#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
58#[derive(Debug, Clone, PartialEq, Eq, Hash)]
59#[cfg_attr(feature = "serde", serde(transparent))]
60pub struct Regex(String);
61
62impl Regex {
63 pub fn new(regex: String) -> Self {
64 Self(regex)
65 }
66
67 /// Check whether the given [Identity] matches this regular expression.
68 pub fn matches(&self, target_user_id: &Identity) -> bool {
69 // TODO: Check if the regex crate supports the same feature set as Henry Spencer's packages.
70
71 let r = regex::RegexBuilder::new(&self.0).build().expect("FIXME");
72 r.is_match(&target_user_id.0)
73 }
74
75 pub fn inner(&self) -> &String {
76 &self.0
77 }
78}
79
80impl fmt::Display for Regex {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 write!(f, "{}", self.0)
83 }
84}