mithril_client/certificate_client/mod.rs
1//! A client which retrieves and validates certificates from an Aggregator.
2//!
3//! In order to do so it defines a [CertificateClient] exposes the following features:
4//! - [get][CertificateClient::get]: get a certificate data from its hash
5//! - [list][CertificateClient::list]: get the list of available certificates
6//! - [verify_chain][CertificateClient::verify_chain]: verify a certificate chain
7//!
8//! # Get a certificate
9//!
10//! To get a certificate using the [ClientBuilder][crate::client::ClientBuilder].
11//!
12//! ```no_run
13//! # async fn run() -> mithril_client::MithrilResult<()> {
14//! use mithril_client::ClientBuilder;
15//!
16//! let client = ClientBuilder::aggregator("YOUR_AGGREGATOR_ENDPOINT", "YOUR_GENESIS_VERIFICATION_KEY").build()?;
17//! let certificate = client.certificate().get("CERTIFICATE_HASH").await?.unwrap();
18//!
19//! println!("Certificate hash={}, signed_message={}", certificate.hash, certificate.signed_message);
20//! # Ok(())
21//! # }
22//! ```
23//!
24//! # List available certificates
25//!
26//! To list available certificates using the [ClientBuilder][crate::client::ClientBuilder].
27//!
28//! ```no_run
29//! # async fn run() -> mithril_client::MithrilResult<()> {
30//! use mithril_client::ClientBuilder;
31//!
32//! let client = mithril_client::ClientBuilder::aggregator("YOUR_AGGREGATOR_ENDPOINT", "YOUR_GENESIS_VERIFICATION_KEY").build()?;
33//! let certificates = client.certificate().list().await?;
34//!
35//! for certificate in certificates {
36//! println!("Certificate hash={}, signed_message={}", certificate.hash, certificate.signed_message);
37//! }
38//! # Ok(())
39//! # }
40//! ```
41//!
42//! # Validate a certificate chain
43//!
44//! To validate a certificate using the [ClientBuilder][crate::client::ClientBuilder].
45//!
46//! ```no_run
47//! # async fn run() -> mithril_client::MithrilResult<()> {
48//! use mithril_client::ClientBuilder;
49//!
50//! let client = ClientBuilder::aggregator("YOUR_AGGREGATOR_ENDPOINT", "YOUR_GENESIS_VERIFICATION_KEY").build()?;
51//! let certificate = client.certificate().verify_chain("CERTIFICATE_HASH").await?;
52//!
53//! println!("Chain of Certificate (hash: {}) is valid", certificate.hash);
54//! # Ok(())
55//! # }
56//! ```
57
58mod api;
59mod fetch;
60mod verify;
61#[cfg(feature = "unstable")]
62mod verify_cache;
63
64pub use api::*;
65pub use verify::MithrilCertificateVerifier;
66#[cfg(feature = "unstable")]
67pub use verify_cache::MemoryCertificateVerifierCache;
68
69#[cfg(test)]
70pub(crate) mod tests_utils {
71 use mithril_common::crypto_helper::ProtocolGenesisVerificationKey;
72 use mithril_common::entities::Certificate;
73 use mithril_common::messages::CertificateMessage;
74 use mockall::predicate::eq;
75 use std::sync::Arc;
76
77 use crate::aggregator_client::{AggregatorRequest, MockAggregatorClient};
78 use crate::feedback::{FeedbackReceiver, FeedbackSender};
79 use crate::test_utils::TestLogger;
80
81 use super::*;
82
83 #[derive(Default)]
84 pub(crate) struct CertificateClientTestBuilder {
85 aggregator_client: MockAggregatorClient,
86 genesis_verification_key: Option<String>,
87 feedback_receivers: Vec<Arc<dyn FeedbackReceiver>>,
88 #[cfg(feature = "unstable")]
89 verifier_cache: Option<Arc<dyn CertificateVerifierCache>>,
90 }
91
92 impl CertificateClientTestBuilder {
93 pub fn config_aggregator_client_mock(
94 mut self,
95 config: impl FnOnce(&mut MockAggregatorClient),
96 ) -> Self {
97 config(&mut self.aggregator_client);
98 self
99 }
100
101 pub fn with_genesis_verification_key(
102 mut self,
103 genesis_verification_key: ProtocolGenesisVerificationKey,
104 ) -> Self {
105 self.genesis_verification_key = Some(genesis_verification_key.try_into().unwrap());
106 self
107 }
108
109 pub fn add_feedback_receiver(
110 mut self,
111 feedback_receiver: Arc<dyn FeedbackReceiver>,
112 ) -> Self {
113 self.feedback_receivers.push(feedback_receiver);
114 self
115 }
116
117 #[cfg(feature = "unstable")]
118 pub fn with_verifier_cache(
119 mut self,
120 verifier_cache: Arc<dyn CertificateVerifierCache>,
121 ) -> Self {
122 self.verifier_cache = Some(verifier_cache);
123 self
124 }
125
126 /// Builds a new [CertificateClient] with the given configuration.
127 ///
128 /// If no genesis verification key is provided, a [MockCertificateVerifier] will be used,
129 /// else a [MithrilCertificateVerifier] will be used.
130 pub fn build(self) -> CertificateClient {
131 let logger = TestLogger::stdout();
132 let aggregator_client = Arc::new(self.aggregator_client);
133
134 let certificate_verifier: Arc<dyn CertificateVerifier> =
135 match self.genesis_verification_key {
136 None => Arc::new(MockCertificateVerifier::new()),
137 Some(genesis_verification_key) => Arc::new(
138 MithrilCertificateVerifier::new(
139 aggregator_client.clone(),
140 &genesis_verification_key,
141 FeedbackSender::new(&self.feedback_receivers),
142 #[cfg(feature = "unstable")]
143 self.verifier_cache,
144 logger.clone(),
145 )
146 .unwrap(),
147 ),
148 };
149
150 CertificateClient::new(aggregator_client.clone(), certificate_verifier, logger)
151 }
152 }
153
154 impl MockAggregatorClient {
155 pub(crate) fn expect_certificate_chain(&mut self, certificate_chain: Vec<Certificate>) {
156 for certificate in certificate_chain {
157 let hash = certificate.hash.clone();
158 let message = serde_json::to_string(
159 &TryInto::<CertificateMessage>::try_into(certificate).unwrap(),
160 )
161 .unwrap();
162 self.expect_get_content()
163 .with(eq(AggregatorRequest::GetCertificate { hash }))
164 .once()
165 .returning(move |_| Ok(message.to_owned()));
166 }
167 }
168 }
169}