1pub mod hkp;
8pub mod wkd;
9
10use std::{
11 io::{Cursor, Read},
12 sync::Arc,
13};
14
15use futures::{stream::FuturesUnordered, StreamExt};
16use http::ureq::http::Uri;
17use tracing::{debug, warn};
18
19use crate::{
20 native::{Deserializable, SignedPublicKey},
21 utils::spawn,
22 Error, Result,
23};
24
25async fn fetch(client: &http::Client, email: &str, key_server: &str) -> Result<SignedPublicKey> {
28 let uri: Uri = key_server
29 .replace("<email>", email)
30 .parse()
31 .map_err(http::Error::from)?;
32
33 let uri = match uri.scheme_str() {
34 Some("hkp") | Some("hkps") => hkp::format_key_server_uri(uri, email).unwrap(),
35 _ => uri,
37 };
38
39 let uri_clone = uri.clone();
40 let res = client
41 .send(move |agent| agent.get(uri_clone).call())
42 .await?;
43
44 let status = res.status();
45 let mut body = res.into_body();
46 let mut body = body.as_reader();
47
48 if !status.is_success() {
49 let mut err = String::new();
50 body.read_to_string(&mut err)
51 .map_err(|err| Error::ReadHttpError(err, uri.clone(), status))?;
52 return Err(Error::GetPublicKeyError(err, uri, status));
53 }
54
55 let mut bytes = Vec::new();
56 body.read_to_end(&mut bytes)
57 .map_err(|err| Error::ReadPublicKeyError(err, uri.clone()))?;
58 let cursor = Cursor::new(bytes);
59 let (pkey, _) = SignedPublicKey::from_armor_single(cursor)
60 .map_err(|err| Error::ParsePublicKeyError(err, uri))?;
61
62 Ok(pkey)
63}
64
65async fn get(
71 client: &http::Client,
72 email: &String,
73 key_servers: &[String],
74) -> Result<SignedPublicKey> {
75 for key_server in key_servers {
76 match fetch(client, email, key_server).await {
77 Ok(pkey) => {
78 debug!("found pgp public key for {email} at {key_server}");
79 return Ok(pkey);
80 }
81 Err(err) => {
82 let msg = format!("cannot get pgp public key for {email} at {key_server}");
83 warn!("{msg}: {err}");
84 debug!("{msg}: {err:?}");
85 continue;
86 }
87 }
88 }
89
90 Err(Error::FindPublicKeyError(email.to_owned()))
91}
92
93pub async fn get_one(email: String, key_servers: Vec<String>) -> Result<SignedPublicKey> {
95 let client = http::Client::new();
96 self::get(&client, &email, &key_servers).await
97}
98
99pub async fn get_all(
101 emails: Vec<String>,
102 key_servers: Vec<String>,
103) -> Vec<(String, Result<SignedPublicKey>)> {
104 let key_servers = Arc::new(key_servers);
105 let client = http::Client::new();
106
107 FuturesUnordered::from_iter(emails.into_iter().map(|email| {
108 let key_servers = key_servers.clone();
109 let client = client.clone();
110 spawn(async move {
111 (
112 email.clone(),
113 self::get(&client, &email, &key_servers).await,
114 )
115 })
116 }))
117 .filter_map(|res| async {
118 match res {
119 Ok(res) => {
120 return Some(res);
121 }
122 Err(err) => {
123 debug!(?err, "skipping failed task");
124 None
125 }
126 }
127 })
128 .collect()
129 .await
130}