1use crate::{
4 discover::{AsDiscovered, DiscoveredAdvisory, DiscoveredContext, DiscoveredVisitor},
5 source::Source,
6};
7use bytes::Bytes;
8use sha2::{Sha256, Sha512};
9use std::{
10 fmt::Debug,
11 future::Future,
12 ops::{Deref, DerefMut},
13};
14use url::Url;
15use walker_common::{
16 retrieve::{RetrievalError, RetrievalMetadata, RetrievedDigest, RetrievedDocument},
17 utils::{openpgp::PublicKey, url::Urlify},
18 validate::source::{KeySource, KeySourceError},
19};
20
21#[derive(Clone, Debug)]
23pub struct RetrievedAdvisory {
24 pub discovered: DiscoveredAdvisory,
26
27 pub data: Bytes,
29 pub signature: Option<String>,
31
32 pub sha256: Option<RetrievedDigest<Sha256>>,
34 pub sha512: Option<RetrievedDigest<Sha512>>,
36
37 pub metadata: RetrievalMetadata,
39}
40
41impl Urlify for RetrievedAdvisory {
42 fn url(&self) -> &Url {
43 &self.url
44 }
45
46 fn relative_base_and_url(&self) -> Option<(&Url, String)> {
47 self.discovered.relative_base_and_url()
48 }
49}
50
51pub trait AsRetrieved: Debug {
53 fn as_retrieved(&self) -> &RetrievedAdvisory;
54}
55
56impl AsDiscovered for RetrievedAdvisory {
57 fn as_discovered(&self) -> &DiscoveredAdvisory {
58 &self.discovered
59 }
60}
61
62impl AsRetrieved for RetrievedAdvisory {
63 fn as_retrieved(&self) -> &RetrievedAdvisory {
64 self
65 }
66}
67
68impl Deref for RetrievedAdvisory {
69 type Target = DiscoveredAdvisory;
70
71 fn deref(&self) -> &Self::Target {
72 &self.discovered
73 }
74}
75
76impl DerefMut for RetrievedAdvisory {
77 fn deref_mut(&mut self) -> &mut Self::Target {
78 &mut self.discovered
79 }
80}
81
82impl RetrievedDocument for RetrievedAdvisory {
83 type Discovered = DiscoveredAdvisory;
84}
85
86pub struct RetrievalContext<'c> {
87 pub discovered: &'c DiscoveredContext<'c>,
88 pub keys: &'c Vec<PublicKey>,
89}
90
91impl<'c> Deref for RetrievalContext<'c> {
92 type Target = DiscoveredContext<'c>;
93
94 fn deref(&self) -> &Self::Target {
95 self.discovered
96 }
97}
98
99pub trait RetrievedVisitor<S: Source> {
100 type Error: std::fmt::Display + Debug;
101 type Context;
102
103 fn visit_context(
104 &self,
105 context: &RetrievalContext,
106 ) -> impl Future<Output = Result<Self::Context, Self::Error>>;
107
108 fn visit_advisory(
109 &self,
110 context: &Self::Context,
111 result: Result<RetrievedAdvisory, RetrievalError<DiscoveredAdvisory, S>>,
112 ) -> impl Future<Output = Result<(), Self::Error>>;
113}
114
115impl<F, E, Fut, S> RetrievedVisitor<S> for F
116where
117 F: Fn(Result<RetrievedAdvisory, RetrievalError<DiscoveredAdvisory, S>>) -> Fut,
118 Fut: Future<Output = Result<(), E>>,
119 E: std::fmt::Display + Debug,
120 S: Source,
121{
122 type Error = E;
123 type Context = ();
124
125 async fn visit_context(
126 &self,
127 _context: &RetrievalContext<'_>,
128 ) -> Result<Self::Context, Self::Error> {
129 Ok(())
130 }
131
132 async fn visit_advisory(
133 &self,
134 _ctx: &Self::Context,
135 outcome: Result<RetrievedAdvisory, RetrievalError<DiscoveredAdvisory, S>>,
136 ) -> Result<(), Self::Error> {
137 self(outcome).await
138 }
139}
140
141pub struct RetrievingVisitor<V: RetrievedVisitor<S>, S: Source + KeySource> {
142 visitor: V,
143 source: S,
144}
145
146impl<V, S> RetrievingVisitor<V, S>
147where
148 V: RetrievedVisitor<S>,
149 S: Source + KeySource,
150{
151 pub fn new(source: S, visitor: V) -> Self {
152 Self { visitor, source }
153 }
154}
155
156#[derive(Debug, thiserror::Error)]
157pub enum Error<VE, SE, KSE>
158where
159 VE: std::fmt::Display + Debug,
160 SE: std::fmt::Display + Debug,
161 KSE: std::fmt::Display + Debug,
162{
163 #[error("Source error: {0}")]
164 Source(SE),
165 #[error("Key source error: {0}")]
166 KeySource(KeySourceError<KSE>),
167 #[error(transparent)]
168 Visitor(VE),
169}
170
171impl<V, S> DiscoveredVisitor for RetrievingVisitor<V, S>
172where
173 V: RetrievedVisitor<S>,
174 S: Source + KeySource,
175{
176 type Error =
177 Error<V::Error, <S as walker_common::source::Source>::Error, <S as KeySource>::Error>;
178 type Context = V::Context;
179
180 async fn visit_context(
181 &self,
182 context: &DiscoveredContext<'_>,
183 ) -> Result<Self::Context, Self::Error> {
184 let mut keys = Vec::with_capacity(context.metadata.public_openpgp_keys.len());
185
186 for key in &context.metadata.public_openpgp_keys {
187 keys.push(
188 self.source
189 .load_public_key(key.into())
190 .await
191 .map_err(Error::KeySource)?,
192 );
193 }
194
195 log::info!(
196 "Loaded {} public key{}",
197 keys.len(),
198 if keys.len() != 1 {
199 "s"
200 } else {
201 Default::default()
202 }
203 );
204 if log::log_enabled!(log::Level::Debug) {
205 for key in keys.iter().flat_map(|k| &k.certs) {
206 log::debug!(" {}", key.key_handle());
207 for id in key.userids() {
208 log::debug!(" {}", id.userid());
209 }
210 }
211 }
212
213 self.visitor
214 .visit_context(&RetrievalContext {
215 discovered: context,
216 keys: &keys,
217 })
218 .await
219 .map_err(Error::Visitor)
220 }
221
222 async fn visit_advisory(
223 &self,
224 context: &Self::Context,
225 discovered: DiscoveredAdvisory,
226 ) -> Result<(), Self::Error> {
227 let advisory = self
228 .source
229 .load_advisory(discovered.clone())
230 .await
231 .map_err(|err| RetrievalError::Source { err, discovered });
232
233 self.visitor
234 .visit_advisory(context, advisory)
235 .await
236 .map_err(Error::Visitor)?;
237
238 Ok(())
239 }
240}