summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authoramesgen <amesgen@amesgen.de>2020-10-14 15:38:04 +0200
committerIgor Matuszewski <igor@sequoia-pgp.org>2020-10-23 12:05:54 +0200
commiteb324f60bbd4184057797f72cc3db34e6160497d (patch)
treec5c5438a2640435c419c8ed496693301dede9544 /net
parent731f01cf5f3699ab738333a65a541d3fb2f25e15 (diff)
update net to futures=0.2
Diffstat (limited to 'net')
-rw-r--r--net/Cargo.toml11
-rw-r--r--net/src/lib.rs153
-rw-r--r--net/src/wkd.rs68
-rw-r--r--net/tests/hkp.rs135
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(())
}