diff options
author | amesgen <amesgen@amesgen.de> | 2020-10-14 15:38:04 +0200 |
---|---|---|
committer | Igor Matuszewski <igor@sequoia-pgp.org> | 2020-10-23 12:05:54 +0200 |
commit | eb324f60bbd4184057797f72cc3db34e6160497d (patch) | |
tree | c5c5438a2640435c419c8ed496693301dede9544 /net | |
parent | 731f01cf5f3699ab738333a65a541d3fb2f25e15 (diff) |
update net to futures=0.2
Diffstat (limited to 'net')
-rw-r--r-- | net/Cargo.toml | 11 | ||||
-rw-r--r-- | net/src/lib.rs | 153 | ||||
-rw-r--r-- | net/src/wkd.rs | 68 | ||||
-rw-r--r-- | net/tests/hkp.rs | 135 |
4 files changed, 133 insertions, 234 deletions
diff --git a/net/Cargo.toml b/net/Cargo.toml index fc0525d8..bb546e3c 100644 --- a/net/Cargo.toml +++ b/net/Cargo.toml @@ -25,22 +25,21 @@ sequoia-openpgp = { path = "../openpgp", version = "0.20", default-features = fa sequoia-core = { path = "../core", version = "0.20" } anyhow = "1" -futures = "0.1" -http = "0.1.5" -hyper = "0.12" -hyper-tls = "0.3" +futures-util = "0.3" +http = "0.2" +hyper = "0.13" +hyper-tls = "0.4" libc = "0.2.33" native-tls = "0.2.0" percent-encoding = "2.1" tempfile = "3.1" thiserror = "1" -tokio-core = "0.1" -tokio-io = "0.1.4" url = "2.1" zbase32 = "0.1.2" [dev-dependencies] rand = { version = "0.7", default-features = false } +tokio = { version = "0.2", features = ["full"] } [features] default = ["compression"] diff --git a/net/src/lib.rs b/net/src/lib.rs index cdd05cc1..d39c62cc 100644 --- a/net/src/lib.rs +++ b/net/src/lib.rs @@ -14,37 +14,20 @@ //! [SKS keyserver]: https://www.sks-keyservers.net/overview-of-pools.php#pool_hkps //! //! ```no_run -//! # use tokio_core; -//! # use sequoia_openpgp as openpgp; -//! # use openpgp::KeyID; +//! # use sequoia_openpgp::KeyID; //! # use sequoia_core::Context; //! # use sequoia_net::{KeyServer, Result}; -//! # use tokio_core::reactor::Core; -//! # fn main() { f().unwrap(); } -//! # fn f() -> Result<()> { -//! let mut core = Core::new().unwrap(); +//! # async fn f() -> Result<()> { //! let ctx = Context::new()?; //! let mut ks = KeyServer::keys_openpgp_org(&ctx)?; -//! let keyid = "31855247603831FD".parse().unwrap(); -//! println!("{:?}", core.run(ks.get(&keyid))); -//! Ok(()) +//! let keyid = "31855247603831FD".parse()?; +//! println!("{:?}", ks.get(&keyid).await?); +//! # Ok(()) //! # } //! ``` #![warn(missing_docs)] -use sequoia_openpgp as openpgp; -use sequoia_core; - -use futures; -use http; -use hyper; -use hyper_tls; -use native_tls; -use percent_encoding; -use url; - -use futures::{future, Future, Stream}; use hyper::client::{ResponseFuture, HttpConnector}; use hyper::header::{CONTENT_LENGTH, CONTENT_TYPE, HeaderValue}; use hyper::{Client, Body, StatusCode, Request}; @@ -56,9 +39,9 @@ use std::convert::From; use std::io::Cursor; use url::Url; -use crate::openpgp::Cert; -use crate::openpgp::parse::Parse; -use crate::openpgp::{KeyID, armor, serialize::Serialize}; +use sequoia_openpgp::Cert; +use sequoia_openpgp::parse::Parse; +use sequoia_openpgp::{KeyID, armor, serialize::Serialize}; use sequoia_core::{Context, NetworkPolicy}; pub mod wkd; @@ -78,8 +61,6 @@ pub struct KeyServer { uri: Url, } -const DNS_WORKER: usize = 4; - impl KeyServer { /// Returns a handle for the given URI. pub fn new(ctx: &Context, uri: &str) -> Result<Self> { @@ -90,7 +71,7 @@ impl KeyServer { "hkp" => Box::new(Client::new()), "hkps" => { Box::new(Client::builder() - .build(HttpsConnector::new(DNS_WORKER)?)) + .build(HttpsConnector::new())) }, _ => return Err(Error::MalformedUri.into()), }; @@ -110,10 +91,10 @@ impl KeyServer { tls.add_root_certificate(cert); let tls = tls.build()?; - let mut http = HttpConnector::new(DNS_WORKER); + let mut http = HttpConnector::new(); http.enforce_http(false); Box::new(Client::builder() - .build(HttpsConnector::from((http, tls)))) + .build(HttpsConnector::from((http, tls.into())))) }; Self::make(ctx, client, uri) @@ -150,78 +131,40 @@ impl KeyServer { } /// Retrieves the key with the given `keyid`. - pub fn get(&mut self, keyid: &KeyID) - -> Box<dyn Future<Item=Cert, Error=anyhow::Error> + 'static> { + pub async fn get(&mut self, keyid: &KeyID) -> Result<Cert> { let keyid_want = keyid.clone(); let uri = self.uri.join( - &format!("pks/lookup?op=get&options=mr&search=0x{:X}", keyid)); - if let Err(e) = uri { - // This shouldn't happen, but better safe than sorry. - return Box::new(future::err(Error::from(e).into())); + &format!("pks/lookup?op=get&options=mr&search=0x{:X}", keyid))?; + + let res = self.client.do_get(uri).await?; + match res.status() { + StatusCode::OK => { + let body = hyper::body::to_bytes(res.into_body()).await?; + let r = armor::Reader::new( + Cursor::new(body), + armor::ReaderMode::Tolerant(Some(armor::Kind::PublicKey)), + ); + let cert = Cert::from_reader(r)?; + if cert.keys().any(|ka| KeyID::from(ka.fingerprint()) == keyid_want) { + Ok(cert) + } else { + Err(Error::MismatchedKeyID(keyid_want, cert).into()) + } + } + StatusCode::NOT_FOUND => Err(Error::NotFound.into()), + n => Err(Error::HttpStatus(n).into()), } - - Box::new(self.client.do_get(uri.unwrap()) - .from_err() - .and_then(|res| { - let status = res.status(); - res.into_body().concat2().from_err() - .and_then(move |body| match status { - StatusCode::OK => { - let c = Cursor::new(body.as_ref()); - let r = armor::Reader::new( - c, - armor::ReaderMode::Tolerant( - Some(armor::Kind::PublicKey))); - match Cert::from_reader(r) { - Ok(cert) => { - if cert.keys().any(|ka| { - KeyID::from(ka.fingerprint()) - == keyid_want - }) { - future::done(Ok(cert)) - } else { - future::err(Error::MismatchedKeyID( - keyid_want, cert).into()) - } - }, - Err(e) => { - future::err(e.into()) - } - } - }, - StatusCode::NOT_FOUND => - future::err(Error::NotFound.into()), - n => future::err(Error::HttpStatus(n).into()), - }) - })) } /// Sends the given key to the server. - pub fn send(&mut self, key: &Cert) - -> Box<dyn Future<Item=(), Error=anyhow::Error> + 'static> { - use crate::openpgp::armor::{Writer, Kind}; + pub async fn send(&mut self, key: &Cert) -> Result<()> { + use sequoia_openpgp::armor::{Writer, Kind}; - let uri = - match self.uri.join("pks/add") { - Err(e) => - // This shouldn't happen, but better safe than sorry. - return Box::new(future::err(Error::from(e).into())), - Ok(u) => u, - }; - - let mut w = match Writer::new(Vec::new(), Kind::PublicKey) { - Ok(v) => v, - Err(e) => return Box::new(future::err(e.into())), - }; + let uri = self.uri.join("pks/add")?; + let mut w = Writer::new(Vec::new(), Kind::PublicKey)?; + key.serialize(&mut w)?; - if let Err(e) = key.serialize(&mut w) { - return Box::new(future::err(e)); - } - - let armored_blob = match w.finalize() { - Ok(v) => v, - Err(e) => return Box::new(future::err(e.into())), - }; + let armored_blob = w.finalize()?; // Prepare to send url-encoded data. let mut post_data = b"keytext=".to_vec(); @@ -229,12 +172,7 @@ impl KeyServer { .collect::<String>().as_bytes()); let length = post_data.len(); - let mut request = match Request::post(url2uri(uri)) - .body(Body::from(post_data)) - { - Ok(r) => r, - Err(e) => return Box::new(future::err(Error::from(e).into())), - }; + let mut request = Request::post(url2uri(uri)).body(Body::from(post_data))?; request.headers_mut().insert( CONTENT_TYPE, HeaderValue::from_static("application/x-www-form-urlencoded")); @@ -243,15 +181,12 @@ impl KeyServer { HeaderValue::from_str(&format!("{}", length)) .expect("cannot fail: only ASCII characters")); - Box::new(self.client.do_request(request) - .from_err() - .and_then(|res| { - match res.status() { - StatusCode::OK => future::ok(()), - StatusCode::NOT_FOUND => future::err(Error::ProtocolViolation.into()), - n => future::err(Error::HttpStatus(n).into()), - } - })) + let res = self.client.do_request(request).await?; + match res.status() { + StatusCode::OK => Ok(()), + StatusCode::NOT_FOUND => Err(Error::ProtocolViolation.into()), + n => Err(Error::HttpStatus(n).into()), + } } } diff --git a/net/src/wkd.rs b/net/src/wkd.rs index 759f17cd..e8fd9bed 100644 --- a/net/src/wkd.rs +++ b/net/src/wkd.rs @@ -21,20 +21,19 @@ use std::fs; use std::path::{Path, PathBuf}; use anyhow::Context; -use futures::{future, Future, Stream}; +use futures_util::future::TryFutureExt; use hyper::{Uri, Client}; use hyper_tls::HttpsConnector; -use url; -use crate::openpgp::{ - self, +use sequoia_openpgp::{ + self as openpgp, Fingerprint, Cert, + parse::Parse, + serialize::Marshal, + types::HashAlgorithm, + cert::prelude::*, }; -use crate::openpgp::parse::Parse; -use crate::openpgp::serialize::Marshal; -use crate::openpgp::types::HashAlgorithm; -use crate::openpgp::cert::prelude::*; use super::{Result, Error}; @@ -264,46 +263,37 @@ fn parse_body<S: AsRef<str>>(body: &[u8], email_address: S) /// # Examples /// /// ```no_run -/// use tokio_core::reactor::Core; -/// use sequoia_net::wkd; -/// +/// # use sequoia_net::{Result, wkd}; +/// # use sequoia_openpgp::Cert; +/// # async fn f() -> Result<()> { /// let email_address = "foo@bar.baz"; -/// let mut core = Core::new().unwrap(); -/// let certs = core.run(wkd::get(&email_address)).unwrap(); +/// let certs: Vec<Cert> = wkd::get(&email_address).await?; +/// # Ok(()) +/// # } /// ``` // XXX: Maybe the direct method should be tried on other errors too. // https://mailarchive.ietf.org/arch/msg/openpgp/6TxZc2dQFLKXtS0Hzmrk963EteE -pub fn get<S: AsRef<str>>(email_address: S) - -> impl Future<Item=Vec<Cert>, Error=anyhow::Error> { +pub async fn get<S: AsRef<str>>(email_address: S) -> Result<Vec<Cert>> { let email = email_address.as_ref().to_string(); - future::lazy(move || -> Result<_> { - // First, prepare URIs and client. - let wkd_url = Url::from(&email)?; + // First, prepare URIs and client. + let wkd_url = Url::from(&email)?; - // WKD must use TLS, so build a client for that. - let https = HttpsConnector::new(4)?; - let client = Client::builder().build::<_, hyper::Body>(https); + // WKD must use TLS, so build a client for that. + let https = HttpsConnector::new(); + let client = Client::builder().build::<_, hyper::Body>(https); + let advanced_uri = wkd_url.to_uri(Variant::Advanced)?; + let direct_uri = wkd_url.to_uri(Variant::Direct)?; - use self::Variant::*; - Ok((email, client, wkd_url.to_uri(Advanced)?, wkd_url.to_uri(Direct)?)) - }).and_then(|(email, client, advanced_uri, direct_uri)| { + let res = client // First, try the Advanced Method. - client.get(advanced_uri) + .get(advanced_uri) // Fall back to the Direct Method. - .or_else(move |_| { - client.get(direct_uri) - }) - .from_err() - .map(|res| (email, res)) - }).and_then(|(email, res)| { - // Join the response body. - res.into_body().concat2().from_err() - .map(|body| (email, body)) - }).and_then(|(email, body)| { - // And parse the response. - parse_body(&body, &email) - }) + .or_else(|_| client.get(direct_uri)) + .await?; + let body = hyper::body::to_bytes(res.into_body()).await?; + + parse_body(&body, &email) } /// Inserts a key into a Web Key Directory. @@ -403,7 +393,7 @@ impl KeyRing { } } -impl crate::openpgp::serialize::Serialize for KeyRing {} +impl openpgp::serialize::Serialize for KeyRing {} impl Marshal for KeyRing { fn serialize(&self, o: &mut dyn std::io::Write) -> openpgp::Result<()> { diff --git a/net/tests/hkp.rs b/net/tests/hkp.rs index ff41d9a8..544c4533 100644 --- a/net/tests/hkp.rs +++ b/net/tests/hkp.rs @@ -1,32 +1,15 @@ -use futures; -use http; -use hyper; -use rand; -use tokio_core; -use url; - -use futures::Stream; -use futures::future::Future; -use futures::sync::oneshot; - use http::{Request, Response}; use hyper::{Server, Body}; -use hyper::service::service_fn; +use hyper::service::{make_service_fn, service_fn}; use hyper::{Method, StatusCode}; use rand::RngCore; use rand::rngs::OsRng; use std::io::Cursor; use std::net::{SocketAddr, IpAddr, Ipv4Addr}; -use std::thread; -use tokio_core::reactor::Core; - -use sequoia_openpgp as openpgp; -use sequoia_core; -use sequoia_net; -use crate::openpgp::armor::Reader; -use crate::openpgp::Cert; -use crate::openpgp::parse::Parse; +use sequoia_openpgp::armor::Reader; +use sequoia_openpgp::Cert; +use sequoia_openpgp::parse::Parse; use sequoia_core::{Context, NetworkPolicy}; use sequoia_net::KeyServer; @@ -65,8 +48,8 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g= const FP: &'static str = "3E8877C877274692975189F5D03F6F865226FE8B"; const ID: &'static str = "D03F6F865226FE8B"; -fn service(req: Request<Body>) - -> Box<dyn Future<Item=Response<Body>, Error=hyper::Error> + Send> { +async fn service(req: Request<Body>) + -> Result<Response<Body>, Box<dyn std::error::Error + Send + Sync>> { let (parts, body) = req.into_parts(); match (parts.method, parts.uri.path()) { (Method::GET, "/pks/lookup") => { @@ -83,34 +66,32 @@ fn service(req: Request<Body>) panic!("Expected query string"); } - Box::new(futures::future::ok(Response::new(Body::from(RESPONSE)))) + Ok(Response::new(Body::from(RESPONSE))) }, (Method::POST, "/pks/add") => { - Box::new( - body.concat2() - .map(|b| { - for (key, value) in url::form_urlencoded::parse(b.as_ref()) { - match key.clone().into_owned().as_ref() { - "keytext" => { - let key = Cert::from_reader( - Reader::new(Cursor::new(value.into_owned()), - None)).unwrap(); - assert_eq!( - key.fingerprint(), - FP.parse() - .unwrap()); - }, - _ => panic!("Bad post: {}:{}", key, value), - } - } - - Response::new(Body::from("Ok")) - })) + let b = hyper::body::to_bytes(body).await?; + + for (key, value) in url::form_urlencoded::parse(b.as_ref()) { + match key.clone().into_owned().as_ref() { + "keytext" => { + let key = Cert::from_reader( + Reader::new(Cursor::new(value.into_owned()), + None)).unwrap(); + assert_eq!( + key.fingerprint(), + FP.parse() + .unwrap()); + }, + _ => panic!("Bad post: {}:{}", key, value), + } + } + + Ok(Response::new(Body::from("Ok"))) }, _ => { - Box::new(futures::future::ok(Response::builder() - .status(StatusCode::NOT_FOUND) - .body(Body::from("Not found")).unwrap())) + Ok(Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::from("Not found")).unwrap()) }, } } @@ -120,61 +101,55 @@ fn service(req: Request<Body>) /// Returns the address, a channel to drop() to kill the server, and /// the thread handle to join the server thread. fn start_server() -> SocketAddr { - let (tx, rx) = oneshot::channel::<SocketAddr>(); - thread::spawn(move || { - let (addr, server) = loop { - let port = OsRng.next_u32() as u16; - let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), - port); - if let Ok(s) = Server::try_bind(&addr) { - break (addr, s); - } - }; - - tx.send(addr).unwrap(); - hyper::rt::run(server - .serve(|| service_fn(service)) - .map_err(|e| panic!("{}", e))); - }); + let (addr, server) = loop { + let port = OsRng.next_u32() as u16; + let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port); + if let Ok(s) = Server::try_bind(&addr) { + break (addr, s); + } + }; + + let start_server = server.serve(make_service_fn(|_| async { + Ok::<_, hyper::Error>(service_fn(service)) + })); + tokio::spawn(start_server); - let addr = rx.wait().unwrap(); addr } -#[test] -fn get() { - let mut core = Core::new().unwrap(); +#[tokio::test] +async fn get() -> anyhow::Result<()> { let ctx = Context::configure() .ephemeral() .network_policy(NetworkPolicy::Insecure) - .build().unwrap(); + .build()?; // Start server. let addr = start_server(); - let mut keyserver = - KeyServer::new(&ctx, &format!("hkp://{}", addr)).unwrap(); - let keyid = ID.parse().unwrap(); - let key = core.run(keyserver.get(&keyid)).unwrap(); + let mut keyserver = KeyServer::new(&ctx, &format!("hkp://{}", addr))?; + let keyid = ID.parse()?; + let key = keyserver.get(&keyid).await?; assert_eq!(key.fingerprint(), FP.parse().unwrap()); + Ok(()) } -#[test] -fn send() { - let mut core = Core::new().unwrap(); +#[tokio::test] +async fn send() -> anyhow::Result<()> { let ctx = Context::configure() .ephemeral() .network_policy(NetworkPolicy::Insecure) - .build().unwrap(); + .build()?; // Start server. let addr = start_server(); eprintln!("{}", format!("hkp://{}", addr)); let mut keyserver = - KeyServer::new(&ctx, &format!("hkp://{}", addr)).unwrap(); - let key = Cert::from_reader(Reader::new(Cursor::new(RESPONSE), - None)).unwrap(); - core.run(keyserver.send(&key)).unwrap(); + KeyServer::new(&ctx, &format!("hkp://{}", addr))?; + let key = Cert::from_reader(Reader::new(Cursor::new(RESPONSE), None))?; + keyserver.send(&key).await?; + + Ok(()) } |